diff --git a/reactos/lib/ntdll/makefile b/reactos/lib/ntdll/makefile index 4d9bfcd3d81..bd5ce87d413 100644 --- a/reactos/lib/ntdll/makefile +++ b/reactos/lib/ntdll/makefile @@ -1,4 +1,4 @@ -# $Id: makefile,v 1.101 2004/05/29 21:55:09 hbirr Exp $ +# $Id: makefile,v 1.102 2004/05/31 19:33:12 gdalsnes Exp $ PATH_TO_TOP = ../.. @@ -19,7 +19,7 @@ TARGET_LFLAGS = -Wl,--file-alignment,0x1000 \ -Wl,--section-alignment,0x1000 \ -nostartfiles -nostdlib -TARGET_SDKLIBS = string.a rosrtl.a +TARGET_SDKLIBS = string.a rosrtl.a rtl.a TARGET_GCCLIBS = gcc @@ -64,48 +64,31 @@ RTL_I386_OBJECTS = \ RTL_OBJECTS = \ rtl/access.o \ - rtl/acl.o \ rtl/apc.o \ rtl/atom.o \ rtl/bitmap.o \ rtl/callback.o \ - rtl/compress.o \ rtl/crc32.o \ rtl/critical.o \ - rtl/dos8dot3.o \ - rtl/error.o \ rtl/encode.o \ - rtl/env.o \ rtl/exception.o \ rtl/handle.o \ - rtl/heap.o \ rtl/image.o \ rtl/intrlck.o \ - rtl/largeint.o \ - rtl/luid.o \ rtl/math.o \ - rtl/mem.o \ rtl/message.o \ rtl/misc.o \ - rtl/nls.o \ rtl/path.o \ rtl/ppb.o \ rtl/process.o \ rtl/propvar.o \ - rtl/random.o \ rtl/rangelist.o \ rtl/registry.o \ rtl/resource.o \ - rtl/sd.o \ - rtl/security.o \ - rtl/sid.o \ rtl/splaytree.o \ rtl/teb.o \ rtl/thread.o \ - rtl/time.o \ - rtl/timezone.o \ - rtl/unicode.o \ - rtl/version.o + rtl/libsupp.o STDIO_OBJECTS = \ stdio/sprintf.o \ diff --git a/reactos/lib/ntdll/rtl/libsupp.c b/reactos/lib/ntdll/rtl/libsupp.c new file mode 100644 index 00000000000..aec6fe44493 --- /dev/null +++ b/reactos/lib/ntdll/rtl/libsupp.c @@ -0,0 +1,57 @@ +/* $Id: libsupp.c,v 1.1 2004/05/31 19:33:59 gdalsnes Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: lib/ntdll/rtl/libsup.c + * PURPOSE: Rtl library support routines + * PROGRAMMER: Gunnar Dalsnes + * UPDATE HISTORY: + * + */ + +#include +#include +#include +#include + +#define NDEBUG +#include + +/* FUNCTIONS ***************************************************************/ + +PVOID +STDCALL +ExAllocatePool( + IN POOL_TYPE PoolType, + IN SIZE_T Bytes +) +{ + return RtlAllocateHeap ( + RtlGetProcessHeap (), + 0, + Bytes); +} + +PVOID +STDCALL +ExAllocatePoolWithTag( + IN POOL_TYPE PoolType, + IN SIZE_T Bytes, + IN ULONG Tag +) +{ + return RtlAllocateHeap ( + RtlGetProcessHeap (), + 0, + Bytes); +} + +VOID +STDCALL +ExFreePool(IN PVOID Mem) +{ + RtlFreeHeap ( + RtlGetProcessHeap (), + 0, + Mem); +} diff --git a/reactos/lib/rtl/.cvsignore b/reactos/lib/rtl/.cvsignore new file mode 100644 index 00000000000..7e8aa746198 --- /dev/null +++ b/reactos/lib/rtl/.cvsignore @@ -0,0 +1,4 @@ +*.o +*.d +*.sym +*.map diff --git a/reactos/lib/rtl/acl.c b/reactos/lib/rtl/acl.c new file mode 100644 index 00000000000..1e27a2ed000 --- /dev/null +++ b/reactos/lib/rtl/acl.c @@ -0,0 +1,631 @@ +/* + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PURPOSE: Security manager + * FILE: lib/rtl/acl.c + * PROGRAMER: David Welch + * REVISION HISTORY: + * 26/07/98: Added stubs for security functions + */ + +/* INCLUDES *****************************************************************/ + +#include +#include + +#define NDEBUG +#include + +/* FUNCTIONS ***************************************************************/ + +BOOLEAN STDCALL +RtlFirstFreeAce(PACL Acl, + PACE* Ace) +{ + PACE Current; + PVOID AclEnd; + ULONG i; + + Current = (PACE)(Acl + 1); + *Ace = NULL; + i = 0; + if (Acl->AceCount == 0) + { + *Ace = Current; + return(TRUE); + } + AclEnd = Acl->AclSize + (PVOID)Acl; + do + { + if ((PVOID)Current >= AclEnd) + { + return(FALSE); + } + if (Current->Header.AceType == ACCESS_ALLOWED_COMPOUND_ACE_TYPE && + Acl->AclRevision < ACL_REVISION3) + { + return(FALSE); + } + Current = (PACE)((PVOID)Current + (ULONG)Current->Header.AceSize); + i++; + } + while (i < Acl->AceCount); + + if ((PVOID)Current < AclEnd) + { + *Ace = Current; + } + + return(TRUE); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlGetAce(PACL Acl, + ULONG AceIndex, + PACE *Ace) +{ + ULONG i; + + *Ace = (PACE)(Acl + 1); + + if (Acl->AclRevision < MIN_ACL_REVISION || + Acl->AclRevision > MAX_ACL_REVISION) + { + return(STATUS_INVALID_PARAMETER); + } + + if (AceIndex >= Acl->AceCount) + { + return(STATUS_INVALID_PARAMETER); + } + + for (i = 0; i < AceIndex; i++) + { + if ((PVOID)*Ace >= (PVOID)Acl + Acl->AclSize) + { + return(STATUS_INVALID_PARAMETER); + } + *Ace = (PACE)((PVOID)(*Ace) + (ULONG)(*Ace)->Header.AceSize); + } + + if ((PVOID)*Ace >= (PVOID)Acl + Acl->AclSize) + { + return(STATUS_INVALID_PARAMETER); + } + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +RtlpAddKnownAce (PACL Acl, + ULONG Revision, + ULONG Flags, + ACCESS_MASK AccessMask, + PSID Sid, + ULONG Type) +{ + PACE Ace; + + if (!RtlValidSid(Sid)) + { + return(STATUS_INVALID_SID); + } + if (Acl->AclRevision > MAX_ACL_REVISION || + Revision > MAX_ACL_REVISION) + { + return(STATUS_UNKNOWN_REVISION); + } + if (Revision < Acl->AclRevision) + { + Revision = Acl->AclRevision; + } + if (!RtlFirstFreeAce(Acl, &Ace)) + { + return(STATUS_INVALID_ACL); + } + if (Ace == NULL) + { + return(STATUS_ALLOTTED_SPACE_EXCEEDED); + } + if (((PVOID)Ace + RtlLengthSid(Sid) + sizeof(ACE)) >= + ((PVOID)Acl + Acl->AclSize)) + { + return(STATUS_ALLOTTED_SPACE_EXCEEDED); + } + Ace->Header.AceFlags = Flags; + Ace->Header.AceType = Type; + Ace->Header.AceSize = RtlLengthSid(Sid) + sizeof(ACE); + Ace->AccessMask = AccessMask; + RtlCopySid(RtlLengthSid(Sid), (PSID)(Ace + 1), Sid); + Acl->AceCount++; + Acl->AclRevision = Revision; + return(STATUS_SUCCESS); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlAddAccessAllowedAce (IN OUT PACL Acl, + IN ULONG Revision, + IN ACCESS_MASK AccessMask, + IN PSID Sid) +{ + return RtlpAddKnownAce (Acl, + Revision, + 0, + AccessMask, + Sid, + ACCESS_ALLOWED_ACE_TYPE); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlAddAccessAllowedAceEx (IN OUT PACL Acl, + IN ULONG Revision, + IN ULONG Flags, + IN ACCESS_MASK AccessMask, + IN PSID Sid) +{ + return RtlpAddKnownAce (Acl, + Revision, + Flags, + AccessMask, + Sid, + ACCESS_ALLOWED_ACE_TYPE); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlAddAccessDeniedAce (PACL Acl, + ULONG Revision, + ACCESS_MASK AccessMask, + PSID Sid) +{ + return RtlpAddKnownAce (Acl, + Revision, + 0, + AccessMask, + Sid, + ACCESS_DENIED_ACE_TYPE); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlAddAccessDeniedAceEx (IN OUT PACL Acl, + IN ULONG Revision, + IN ULONG Flags, + IN ACCESS_MASK AccessMask, + IN PSID Sid) +{ + return RtlpAddKnownAce (Acl, + Revision, + Flags, + AccessMask, + Sid, + ACCESS_DENIED_ACE_TYPE); +} + + +static VOID +RtlpAddData(PVOID AceList, + ULONG AceListLength, + PVOID Ace, + ULONG Offset) +{ + if (Offset > 0) + { + memcpy((PUCHAR)Ace + AceListLength, + Ace, + Offset); + } + + if (AceListLength != 0) + { + memcpy(Ace, + AceList, + AceListLength); + } +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlAddAce(PACL Acl, + ULONG AclRevision, + ULONG StartingIndex, + PACE AceList, + ULONG AceListLength) +{ + PACE Ace; + ULONG i; + PACE Current; + ULONG j; + + if (Acl->AclRevision < MIN_ACL_REVISION || + Acl->AclRevision > MAX_ACL_REVISION) + { + return(STATUS_INVALID_PARAMETER); + } + + if (!RtlFirstFreeAce(Acl,&Ace)) + { + return(STATUS_INVALID_PARAMETER); + } + + if (Acl->AclRevision <= AclRevision) + { + AclRevision = Acl->AclRevision; + } + + if (((PVOID)AceList + AceListLength) <= (PVOID)AceList) + { + return(STATUS_INVALID_PARAMETER); + } + + i = 0; + Current = (PACE)(Acl + 1); + while ((PVOID)Current < ((PVOID)AceList + AceListLength)) + { + if (AceList->Header.AceType == ACCESS_ALLOWED_COMPOUND_ACE_TYPE && + AclRevision < ACL_REVISION3) + { + return(STATUS_INVALID_PARAMETER); + } + Current = (PACE)((PVOID)Current + Current->Header.AceSize); + } + + if (Ace == NULL) + { + return(STATUS_BUFFER_TOO_SMALL); + } + + if (((PVOID)Ace + AceListLength) >= ((PVOID)Acl + Acl->AclSize)) + { + return(STATUS_BUFFER_TOO_SMALL); + } + + if (StartingIndex != 0) + { + if (Acl->AceCount > 0) + { + Current = (PACE)(Acl + 1); + for (j = 0; j < StartingIndex; j++) + { + Current = (PACE)((PVOID)Current + Current->Header.AceSize); + } + } + } + + RtlpAddData(AceList, + AceListLength, + Current, + (ULONG)Ace - (ULONG)Current); + Acl->AceCount = Acl->AceCount + i; + Acl->AclRevision = AclRevision; + + return(STATUS_SUCCESS); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlAddAuditAccessAce(PACL Acl, + ULONG Revision, + ACCESS_MASK AccessMask, + PSID Sid, + BOOLEAN Success, + BOOLEAN Failure) +{ + PACE Ace; + ULONG Flags = 0; + + if (Success != FALSE) + { + Flags |= SUCCESSFUL_ACCESS_ACE_FLAG; + } + + if (Failure != FALSE) + { + Flags |= FAILED_ACCESS_ACE_FLAG; + } + + if (!RtlValidSid(Sid)) + { + return(STATUS_INVALID_SID); + } + + if (Acl->AclRevision > MAX_ACL_REVISION || + Revision > MAX_ACL_REVISION) + { + return(STATUS_REVISION_MISMATCH); + } + + if (Revision < Acl->AclRevision) + { + Revision = Acl->AclRevision; + } + + if (!RtlFirstFreeAce(Acl, &Ace)) + { + return(STATUS_INVALID_ACL); + } + + if (Ace == NULL) + { + return(STATUS_ALLOTTED_SPACE_EXCEEDED); + } + + if (((PVOID)Ace + RtlLengthSid(Sid) + sizeof(ACE)) >= ((PVOID)Acl + Acl->AclSize)) + { + return(STATUS_ALLOTTED_SPACE_EXCEEDED); + } + + Ace->Header.AceFlags = Flags; + Ace->Header.AceType = SYSTEM_AUDIT_ACE_TYPE; + Ace->Header.AceSize = RtlLengthSid(Sid) + sizeof(ACE); + Ace->AccessMask = AccessMask; + RtlCopySid(RtlLengthSid(Sid), + (PSID)(Ace + 1), + Sid); + Acl->AceCount++; + Acl->AclRevision = Revision; + + return(STATUS_SUCCESS); +} + + +static VOID +RtlpDeleteData(PVOID Ace, + ULONG AceSize, + ULONG Offset) +{ + if (AceSize < Offset) + { + memcpy(Ace, + (PUCHAR)Ace + AceSize, + Offset - AceSize); + } + + if (Offset - AceSize < Offset) + { + memset((PUCHAR)Ace + Offset - AceSize, + 0, + AceSize); + } +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlDeleteAce(PACL Acl, + ULONG AceIndex) +{ + PACE Ace; + PACE Current; + + if (Acl->AclRevision < MIN_ACL_REVISION || + Acl->AclRevision > MAX_ACL_REVISION) + { + return(STATUS_INVALID_PARAMETER); + } + + if (Acl->AceCount <= AceIndex) + { + return(STATUS_INVALID_PARAMETER); + } + + if (!RtlFirstFreeAce(Acl, &Ace)) + { + return(STATUS_INVALID_PARAMETER); + } + + Current = (PACE)(Acl + 1); + + while(AceIndex--) + { + Current = (PACE)((PVOID)Current + Current->Header.AceSize); + } + + RtlpDeleteData(Current, + Current->Header.AceSize, + Ace - Current); + Acl->AceCount++; + + return(STATUS_SUCCESS); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlCreateAcl(PACL Acl, + ULONG AclSize, + ULONG AclRevision) +{ + if (AclSize < 8) + { + return(STATUS_BUFFER_TOO_SMALL); + } + + if (AclRevision < MIN_ACL_REVISION || + AclRevision > MAX_ACL_REVISION) + { + return(STATUS_INVALID_PARAMETER); + } + + if (AclSize > 0xffff) + { + return(STATUS_INVALID_PARAMETER); + } + + AclSize = AclSize & ~(0x3); + Acl->AclSize = AclSize; + Acl->AclRevision = AclRevision; + Acl->AceCount = 0; + Acl->Sbz1 = 0; + Acl->Sbz2 = 0; + + return(STATUS_SUCCESS); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlQueryInformationAcl(PACL Acl, + PVOID Information, + ULONG InformationLength, + ACL_INFORMATION_CLASS InformationClass) +{ + PACE Ace; + + if (Acl->AclRevision < MIN_ACL_REVISION || + Acl->AclRevision > MAX_ACL_REVISION) + { + return(STATUS_INVALID_PARAMETER); + } + + switch (InformationClass) + { + case AclRevisionInformation: + { + PACL_REVISION_INFORMATION Info = (PACL_REVISION_INFORMATION)Information; + + if (InformationLength < sizeof(ACL_REVISION_INFORMATION)) + { + return(STATUS_BUFFER_TOO_SMALL); + } + Info->AclRevision = Acl->AclRevision; + } + break; + + case AclSizeInformation: + { + PACL_SIZE_INFORMATION Info = (PACL_SIZE_INFORMATION)Information; + + if (InformationLength < sizeof(ACL_SIZE_INFORMATION)) + { + return(STATUS_BUFFER_TOO_SMALL); + } + + if (!RtlFirstFreeAce(Acl, &Ace)) + { + return(STATUS_INVALID_PARAMETER); + } + + Info->AceCount = Acl->AceCount; + if (Ace != NULL) + { + Info->AclBytesInUse = (PVOID)Ace - (PVOID)Acl; + Info->AclBytesFree = Acl->AclSize - Info->AclBytesInUse; + } + else + { + Info->AclBytesInUse = Acl->AclSize; + Info->AclBytesFree = 0; + } + } + break; + + default: + return(STATUS_INVALID_INFO_CLASS); + } + + return(STATUS_SUCCESS); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlSetInformationAcl(PACL Acl, + PVOID Information, + ULONG InformationLength, + ACL_INFORMATION_CLASS InformationClass) +{ + if (Acl->AclRevision < MIN_ACL_REVISION || + Acl->AclRevision > MAX_ACL_REVISION) + { + return(STATUS_INVALID_PARAMETER); + } + + switch (InformationClass) + { + case AclRevisionInformation: + { + PACL_REVISION_INFORMATION Info = (PACL_REVISION_INFORMATION)Information; + + if (InformationLength < sizeof(ACL_REVISION_INFORMATION)) + { + return(STATUS_BUFFER_TOO_SMALL); + } + + if (Acl->AclRevision >= Info->AclRevision) + { + return(STATUS_INVALID_PARAMETER); + } + + Acl->AclRevision = Info->AclRevision; + } + break; + + default: + return(STATUS_INVALID_INFO_CLASS); + } + + return(STATUS_SUCCESS); +} + + +/* + * @implemented + */ +BOOLEAN STDCALL +RtlValidAcl (PACL Acl) +{ + PACE Ace; + USHORT Size; + + Size = (Acl->AclSize + 3) & ~3; + + if (Acl->AclRevision < MIN_ACL_REVISION || + Acl->AclRevision > MAX_ACL_REVISION) + { + return(FALSE); + } + + if (Size != Acl->AclSize) + { + return(FALSE); + } + + return(RtlFirstFreeAce(Acl, &Ace)); +} + +/* EOF */ diff --git a/reactos/lib/rtl/compress.c b/reactos/lib/rtl/compress.c new file mode 100644 index 00000000000..2a5a5ce34bb --- /dev/null +++ b/reactos/lib/rtl/compress.c @@ -0,0 +1,233 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: compress.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PURPOSE: Compression and decompression functions + * FILE: lib/rtl/compress.c + * PROGRAMER: Eric Kohl (ekohl@rz-online.de) + */ + +/* INCLUDES *****************************************************************/ + +#include + +#define NDEBUG +#include + + +/* MACROS *******************************************************************/ + +#define COMPRESSION_FORMAT_MASK 0x00FF +#define COMPRESSION_ENGINE_MASK 0xFF00 + + + + +/* FUNCTIONS ****************************************************************/ + + +static NTSTATUS +RtlpCompressBufferLZNT1(USHORT Engine, + PUCHAR UncompressedBuffer, + ULONG UncompressedBufferSize, + PUCHAR CompressedBuffer, + ULONG CompressedBufferSize, + ULONG UncompressedChunkSize, + PULONG FinalCompressedSize, + PVOID WorkSpace) +{ + return(STATUS_NOT_IMPLEMENTED); +} + + +static NTSTATUS +RtlpWorkSpaceSizeLZNT1(USHORT Engine, + PULONG BufferAndWorkSpaceSize, + PULONG FragmentWorkSpaceSize) +{ + if (Engine == COMPRESSION_ENGINE_STANDARD) + { + *BufferAndWorkSpaceSize = 0x8010; + *FragmentWorkSpaceSize = 0x1000; + return(STATUS_SUCCESS); + } + else if (Engine == COMPRESSION_ENGINE_MAXIMUM) + { + *BufferAndWorkSpaceSize = 0x10; + *FragmentWorkSpaceSize = 0x1000; + return(STATUS_SUCCESS); + } + + return(STATUS_NOT_SUPPORTED); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlCompressBuffer(IN USHORT CompressionFormatAndEngine, + IN PUCHAR UncompressedBuffer, + IN ULONG UncompressedBufferSize, + OUT PUCHAR CompressedBuffer, + IN ULONG CompressedBufferSize, + IN ULONG UncompressedChunkSize, + OUT PULONG FinalCompressedSize, + IN PVOID WorkSpace) +{ + USHORT Format = CompressionFormatAndEngine & COMPRESSION_FORMAT_MASK; + USHORT Engine = CompressionFormatAndEngine & COMPRESSION_ENGINE_MASK; + + if ((Format == COMPRESSION_FORMAT_NONE) || + (Format == COMPRESSION_FORMAT_DEFAULT)) + return(STATUS_INVALID_PARAMETER); + + if (Format == COMPRESSION_FORMAT_LZNT1) + return(RtlpCompressBufferLZNT1(Engine, + UncompressedBuffer, + UncompressedBufferSize, + CompressedBuffer, + CompressedBufferSize, + UncompressedChunkSize, + FinalCompressedSize, + WorkSpace)); + + return(STATUS_UNSUPPORTED_COMPRESSION); +} + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlCompressChunks(IN PUCHAR UncompressedBuffer, + IN ULONG UncompressedBufferSize, + OUT PUCHAR CompressedBuffer, + IN ULONG CompressedBufferSize, + IN OUT PCOMPRESSED_DATA_INFO CompressedDataInfo, + IN ULONG CompressedDataInfoLength, + IN PVOID WorkSpace) +{ + return(STATUS_NOT_IMPLEMENTED); +} + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlDecompressBuffer(IN USHORT CompressionFormat, + OUT PUCHAR UncompressedBuffer, + IN ULONG UncompressedBufferSize, + IN PUCHAR CompressedBuffer, + IN ULONG CompressedBufferSize, + OUT PULONG FinalUncompressedSize) +{ + return(STATUS_NOT_IMPLEMENTED); +} + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlDecompressChunks(OUT PUCHAR UncompressedBuffer, + IN ULONG UncompressedBufferSize, + IN PUCHAR CompressedBuffer, + IN ULONG CompressedBufferSize, + IN PUCHAR CompressedTail, + IN ULONG CompressedTailSize, + IN PCOMPRESSED_DATA_INFO CompressedDataInfo) +{ + return(STATUS_NOT_IMPLEMENTED); +} + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlDecompressFragment(IN USHORT CompressionFormat, + OUT PUCHAR UncompressedFragment, + IN ULONG UncompressedFragmentSize, + IN PUCHAR CompressedBuffer, + IN ULONG CompressedBufferSize, + IN ULONG FragmentOffset, + OUT PULONG FinalUncompressedSize, + IN PVOID WorkSpace) +{ + return(STATUS_NOT_IMPLEMENTED); +} + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlDescribeChunk(IN USHORT CompressionFormat, + IN OUT PUCHAR *CompressedBuffer, + IN PUCHAR EndOfCompressedBufferPlus1, + OUT PUCHAR *ChunkBuffer, + OUT PULONG ChunkSize) +{ + return(STATUS_NOT_IMPLEMENTED); +} + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlGetCompressionWorkSpaceSize(IN USHORT CompressionFormatAndEngine, + OUT PULONG CompressBufferAndWorkSpaceSize, + OUT PULONG CompressFragmentWorkSpaceSize) +{ + USHORT Format = CompressionFormatAndEngine & COMPRESSION_FORMAT_MASK; + USHORT Engine = CompressionFormatAndEngine & COMPRESSION_ENGINE_MASK; + + if ((Format == COMPRESSION_FORMAT_NONE) || + (Format == COMPRESSION_FORMAT_DEFAULT)) + return(STATUS_INVALID_PARAMETER); + + if (Format == COMPRESSION_FORMAT_LZNT1) + return(RtlpWorkSpaceSizeLZNT1(Engine, + CompressBufferAndWorkSpaceSize, + CompressFragmentWorkSpaceSize)); + + return(STATUS_UNSUPPORTED_COMPRESSION); +} + + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlReserveChunk(IN USHORT CompressionFormat, + IN OUT PUCHAR *CompressedBuffer, + IN PUCHAR EndOfCompressedBufferPlus1, + OUT PUCHAR *ChunkBuffer, + IN ULONG ChunkSize) +{ + return(STATUS_NOT_IMPLEMENTED); +} + +/* EOF */ diff --git a/reactos/lib/rtl/dos8dot3.c b/reactos/lib/rtl/dos8dot3.c new file mode 100644 index 00000000000..5bd64ca338b --- /dev/null +++ b/reactos/lib/rtl/dos8dot3.c @@ -0,0 +1,336 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: dos8dot3.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: lib/rtl/dos8dot3.c + * PURPOSE: Short name (8.3 name) functions + * PROGRAMMER: Eric Kohl + */ + +/* INCLUDES ******************************************************************/ + +#include +#include + +#define NDEBUG +#include + + +/* CONSTANTS *****************************************************************/ + +const PCHAR RtlpShortIllegals = " ;+=[],\"*\\<>/?:|"; + + +/* FUNCTIONS *****************************************************************/ + +static BOOLEAN +RtlpIsShortIllegal(CHAR Char) +{ + return strchr(RtlpShortIllegals, Char) ? TRUE : FALSE; +} + +static USHORT +RtlpGetCheckSum(PUNICODE_STRING Name) +{ + USHORT Hash = 0; + ULONG Length; + PWCHAR c; + + Length = Name->Length / sizeof(WCHAR); + c = Name->Buffer; + while(Length--) + { + Hash = (Hash + (*c << 4) + (*c >> 4)) * 11; + c++; + } + return Hash; +} + +static ULONG +RtlpGetIndexLength(ULONG Index) +{ + ULONG Length = 0; + while (Index) + { + Index /= 10; + Length++; + } + return Length ? Length : 1; +} + + +/* + * @implemented + */ +VOID STDCALL +RtlGenerate8dot3Name(IN PUNICODE_STRING Name, + IN BOOLEAN AllowExtendedCharacters, + IN OUT PGENERATE_NAME_CONTEXT Context, + OUT PUNICODE_STRING Name8dot3) +{ + ULONG Count; + WCHAR NameBuffer[8]; + WCHAR ExtBuffer[4]; + ULONG StrLength; + ULONG NameLength; + ULONG ExtLength; + ULONG CopyLength; + ULONG DotPos; + ULONG i, j; + ULONG IndexLength; + ULONG CurrentIndex; + USHORT Checksum; + CHAR c; + + StrLength = Name->Length / sizeof(WCHAR); + DPRINT("StrLength: %hu\n", StrLength); + + /* Find last dot in Name */ + DotPos = 0; + for (i = 0; i < StrLength; i++) + { + if (Name->Buffer[i] == L'.') + { + DotPos = i; + } + } + + if (DotPos == 0) + { + DotPos = i; + } + DPRINT("DotPos: %hu\n", DotPos); + + /* Copy name (6 valid characters max) */ + for (i = 0, NameLength = 0; NameLength < 6 && i < DotPos; i++) + { + c = 0; + RtlUpcaseUnicodeToOemN(&c, sizeof(CHAR), &Count, &Name->Buffer[i], sizeof(WCHAR)); + if (Count != 1 || c == 0 || RtlpIsShortIllegal(c)) + { + NameBuffer[NameLength++] = L'_'; + } + else if (c != '.') + { + NameBuffer[NameLength++] = (WCHAR)c; + } + } + + DPRINT("NameBuffer: '%.08S'\n", NameBuffer); + DPRINT("NameLength: %hu\n", NameLength); + + /* Copy extension (4 valid characters max) */ + if (DotPos < StrLength) + { + for (i = DotPos, ExtLength = 0; ExtLength < 4 && i < StrLength; i++) + { + c = 0; + RtlUpcaseUnicodeToOemN(&c, sizeof(CHAR), &Count, &Name->Buffer[i], sizeof(WCHAR)); + if (Count != 1 || c == 0 || RtlpIsShortIllegal(Name->Buffer[i])) + { + ExtBuffer[ExtLength++] = L'_'; + } + else + { + ExtBuffer[ExtLength++] = c; + } + } + } + else + { + ExtLength = 0; + } + DPRINT("ExtBuffer: '%.04S'\n", ExtBuffer); + DPRINT("ExtLength: %hu\n", ExtLength); + + /* Determine next index */ + IndexLength = RtlpGetIndexLength(Context->LastIndexValue); + if (Context->CheckSumInserted) + { + CopyLength = min(NameLength, 8 - 4 - 1 - IndexLength); + Checksum = RtlpGetCheckSum(Name); + } + else + { + CopyLength = min(NameLength, 8 - 1 - IndexLength); + Checksum = 0; + } + + DPRINT("CopyLength: %hu\n", CopyLength); + + if ((Context->NameLength == CopyLength) && + (wcsncmp(Context->NameBuffer, NameBuffer, CopyLength) == 0) && + (Context->ExtensionLength == ExtLength) && + (wcsncmp(Context->ExtensionBuffer, ExtBuffer, ExtLength) == 0) && + (Checksum == Context->Checksum) && + (Context->LastIndexValue < 999)) + { + CHECKPOINT; + Context->LastIndexValue++; + if (Context->CheckSumInserted == FALSE && + Context->LastIndexValue > 9) + { + Context->CheckSumInserted = TRUE; + Context->LastIndexValue = 1; + Context->Checksum = RtlpGetCheckSum(Name); + } + } + else + { + CHECKPOINT; + Context->LastIndexValue = 1; + Context->CheckSumInserted = FALSE; + } + + IndexLength = RtlpGetIndexLength(Context->LastIndexValue); + + DPRINT("CurrentIndex: %hu, IndexLength %hu\n", Context->LastIndexValue, IndexLength); + + if (Context->CheckSumInserted) + { + CopyLength = min(NameLength, 8 - 4 - 1 - IndexLength); + } + else + { + CopyLength = min(NameLength, 8 - 1 - IndexLength); + } + + /* Build the short name */ + memcpy(Name8dot3->Buffer, NameBuffer, CopyLength * sizeof(WCHAR)); + j = CopyLength; + if (Context->CheckSumInserted) + { + j += 3; + Checksum = Context->Checksum; + for (i = 0; i < 4; i++) + { + Name8dot3->Buffer[j--] = (Checksum % 16) > 9 ? (Checksum % 16) + L'A' - 10 : (Checksum % 16) + L'0'; + Checksum /= 16; + } + j = CopyLength + 4; + } + Name8dot3->Buffer[j++] = L'~'; + j += IndexLength - 1; + CurrentIndex = Context->LastIndexValue; + for (i = 0; i < IndexLength; i++) + { + Name8dot3->Buffer[j--] = (CurrentIndex % 10) + L'0'; + CurrentIndex /= 10; + } + j += IndexLength + 1; + + memcpy(Name8dot3->Buffer + j, ExtBuffer, ExtLength * sizeof(WCHAR)); + Name8dot3->Length = (j + ExtLength) * sizeof(WCHAR); + + DPRINT("Name8dot3: '%wZ'\n", Name8dot3); + + /* Update context */ + Context->NameLength = CopyLength; + Context->ExtensionLength = ExtLength; + memcpy(Context->NameBuffer, NameBuffer, CopyLength * sizeof(WCHAR)); + memcpy(Context->ExtensionBuffer, ExtBuffer, ExtLength * sizeof(WCHAR)); +} + + +/* + * @implemented + */ +BOOLEAN STDCALL +RtlIsNameLegalDOS8Dot3(IN PUNICODE_STRING UnicodeName, + IN PANSI_STRING AnsiName, + OUT PBOOLEAN SpacesFound) +{ + PANSI_STRING name = AnsiName; + ANSI_STRING DummyString; + CHAR Buffer[12]; + char *str; + ULONG Length; + ULONG i; + NTSTATUS Status; + BOOLEAN HasSpace = FALSE; + BOOLEAN HasDot = FALSE; + + if (UnicodeName->Length > 24) + { + return(FALSE); /* name too long */ + } + + if (!name) + { + name = &DummyString; + name->Length = 0; + name->MaximumLength = 12; + name->Buffer = Buffer; + } + + Status = RtlUpcaseUnicodeStringToCountedOemString(name, + UnicodeName, + FALSE); + if (!NT_SUCCESS(Status)) + { + return(FALSE); + } + + Length = name->Length; + str = name->Buffer; + + if (!(Length == 1 && *str == '.') && + !(Length == 2 && *str == '.' && *(str + 1) == '.')) + { + for (i = 0; i < Length; i++, str++) + { + switch (*str) + { + case ' ': + HasSpace = TRUE; + break; + + case '.': + if ((HasDot) || /* two or more dots */ + (i == 0) || /* dot is first char */ + (i + 1 == Length) || /* dot is last char */ + (Length - i > 4) || /* more than 3 chars of extension */ + (HasDot == FALSE && i > 8)) /* name is longer than 8 chars */ + return(FALSE); + HasDot = TRUE; + break; + default: + if (RtlpIsShortIllegal(*str)) + { + return(FALSE); + } + } + } + } + + /* Name is longer than 8 chars and does not have an extension */ + if (Length > 8 && HasDot == FALSE) + { + return(FALSE); + } + + if (SpacesFound) + *SpacesFound = HasSpace; + + return(TRUE); +} + +/* EOF */ diff --git a/reactos/lib/rtl/env.c b/reactos/lib/rtl/env.c new file mode 100644 index 00000000000..257b0dc193b --- /dev/null +++ b/reactos/lib/rtl/env.c @@ -0,0 +1,522 @@ +/* $Id: env.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: lib/rtl/env.c + * PURPOSE: Environment functions + * PROGRAMMER: Eric Kohl + * UPDATE HISTORY: + * Created 30/09/98 + */ + +/* INCLUDES ******************************************************************/ + +#include +#include +#include +#include + +#define NDEBUG +#include + + + +/* FUNCTIONS *****************************************************************/ + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlCreateEnvironment(BOOLEAN Inherit, + PWSTR *Environment) +{ + MEMORY_BASIC_INFORMATION MemInfo; + PVOID EnvPtr = NULL; + NTSTATUS Status = STATUS_SUCCESS; + ULONG RegionSize = PAGE_SIZE; + + if (Inherit == TRUE) + { + RtlAcquirePebLock(); + + if (NtCurrentPeb()->ProcessParameters->Environment != NULL) + { + Status = NtQueryVirtualMemory(NtCurrentProcess(), + NtCurrentPeb()->ProcessParameters->Environment, + MemoryBasicInformation, + &MemInfo, + sizeof(MEMORY_BASIC_INFORMATION), + NULL); + if (!NT_SUCCESS(Status)) + { + RtlReleasePebLock(); + *Environment = NULL; + return(Status); + } + + RegionSize = MemInfo.RegionSize; + Status = NtAllocateVirtualMemory(NtCurrentProcess(), + &EnvPtr, + 0, + &RegionSize, + MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + RtlReleasePebLock(); + *Environment = NULL; + return(Status); + } + + memmove(EnvPtr, + NtCurrentPeb ()->ProcessParameters->Environment, + MemInfo.RegionSize); + + *Environment = EnvPtr; + } + + RtlReleasePebLock (); + } + else + { + Status = NtAllocateVirtualMemory(NtCurrentProcess(), + &EnvPtr, + 0, + &RegionSize, + MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE); + if (NT_SUCCESS(Status)) + { + memset(EnvPtr, + 0, + RegionSize); + *Environment = EnvPtr; + } + } + + return(Status); +} + + +/* + * @implemented + */ +VOID STDCALL +RtlDestroyEnvironment(PWSTR Environment) +{ + ULONG Size = 0; + + NtFreeVirtualMemory(NtCurrentProcess(), + (PVOID*)&Environment, + &Size, + MEM_RELEASE); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlExpandEnvironmentStrings_U(PWSTR Environment, + PUNICODE_STRING Source, + PUNICODE_STRING Destination, + PULONG Length) +{ + UNICODE_STRING var; + UNICODE_STRING val; + NTSTATUS Status = STATUS_SUCCESS; + BOOLEAN flag = FALSE; + PWSTR s; + PWSTR d; + PWSTR w; + int src_len; + int dst_max; + int tail; + + DPRINT("RtlExpandEnvironmentStrings_U %p %wZ %p %p\n", + Environment, Source, Destination, Length); + + src_len = Source->Length / sizeof(WCHAR); + s = Source->Buffer; + dst_max = Destination->MaximumLength / sizeof(WCHAR); + d = Destination->Buffer; + + while (src_len) + { + if (*s == L'%') + { + if (flag) + { + flag = FALSE; + goto copy; + } + w = s + 1; + tail = src_len - 1; + while (*w != L'%' && tail) + { + w++; + tail--; + } + if (!tail) + goto copy; + + var.Length = (w - ( s + 1)) * sizeof(WCHAR); + var.MaximumLength = var.Length; + var.Buffer = s + 1; + + val.Length = 0; + val.MaximumLength = dst_max * sizeof(WCHAR); + val.Buffer = d; + Status = RtlQueryEnvironmentVariable_U (Environment, &var, &val); + if (NT_SUCCESS(Status)) + { + d += val.Length / sizeof(WCHAR); + dst_max -= val.Length / sizeof(WCHAR); + s = w + 1; + src_len = tail - 1; + continue; + } + /* variable not found or buffer too small, just copy %var% */ + flag = TRUE; + } +copy: + if (!dst_max) + { + Status = STATUS_BUFFER_TOO_SMALL; + break; + } + + *d++ = *s++; + dst_max--; + src_len--; + } + + Destination->Length = (d - Destination->Buffer) * sizeof(WCHAR); + if (Length != NULL) + *Length = Destination->Length; + if (dst_max) + Destination->Buffer[Destination->Length / sizeof(WCHAR)] = 0; + + DPRINT("Destination %wZ\n", Destination); + return(Status); +} + + +/* + * @implemented + */ +VOID STDCALL +RtlSetCurrentEnvironment(PWSTR NewEnvironment, + PWSTR *OldEnvironment) +{ + PVOID EnvPtr; + + DPRINT("NewEnvironment %x OldEnvironment %x\n", + NewEnvironment, OldEnvironment); + + RtlAcquirePebLock(); + + EnvPtr = NtCurrentPeb()->ProcessParameters->Environment; + NtCurrentPeb()->ProcessParameters->Environment = NewEnvironment; + + if (OldEnvironment != NULL) + *OldEnvironment = EnvPtr; + + RtlReleasePebLock(); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlSetEnvironmentVariable(PWSTR *Environment, + PUNICODE_STRING Name, + PUNICODE_STRING Value) +{ + MEMORY_BASIC_INFORMATION mbi; + UNICODE_STRING var; + int hole_len, new_len, env_len = 0; + WCHAR *new_env = 0, *env_end = 0, *wcs, *env, *val = 0, *tail = 0, *hole = 0; + PWSTR head = NULL; + ULONG size = 0, new_size; + LONG f = 1; + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT("RtlSetEnvironmentVariable(Environment %p Name %wZ Value %wZ)\n", + Environment, Name, Value); + + if (Environment) + { + env = *Environment; + } + else + { + RtlAcquirePebLock(); + env = NtCurrentPeb()->ProcessParameters->Environment; + } + + if (env) + { + /* get environment length */ + wcs = env_end = env; + do + { + env_end += wcslen(env_end) + 1; + } + while (*env_end); + env_end++; + env_len = env_end - env; + DPRINT("environment length %ld characters\n", env_len); + + /* find where to insert */ + while (*wcs) + { + var.Buffer = wcs++; + wcs = wcschr(wcs, L'='); + if (wcs == NULL) + { + wcs = var.Buffer + wcslen(var.Buffer); + } + if (*wcs) + { + var.Length = (wcs - var.Buffer) * sizeof(WCHAR); + var.MaximumLength = var.Length; + val = ++wcs; + wcs += wcslen(wcs); + f = RtlCompareUnicodeString(&var, Name, TRUE); + if (f >= 0) + { + if (f) /* Insert before found */ + { + hole = tail = var.Buffer; + } + else /* Exact match */ + { + head = var.Buffer; + tail = ++wcs; + hole = val; + } + goto found; + } + } + wcs++; + } + hole = tail = wcs; /* Append to environment */ + } + +found: + if (Value->Length > 0) + { + hole_len = tail - hole; + /* calculate new environment size */ + new_size = Value->Length + sizeof(WCHAR); + /* adding new variable */ + if (f) + new_size += Name->Length + sizeof(WCHAR); + new_len = new_size / sizeof(WCHAR); + if (hole_len < new_len) + { + /* enlarge environment size */ + /* check the size of available memory */ + new_size += (env_len - hole_len) * sizeof(WCHAR); + new_size = ROUNDUP(new_size, PAGE_SIZE); + mbi.RegionSize = 0; + DPRINT("new_size %lu\n", new_size); + + if (env) + { + Status = NtQueryVirtualMemory(NtCurrentProcess(), + env, + MemoryBasicInformation, + &mbi, + sizeof(MEMORY_BASIC_INFORMATION), + NULL); + if (!NT_SUCCESS(Status)) + { + if (Environment == NULL) + { + RtlReleasePebLock(); + } + return(Status); + } + } + + if (new_size > mbi.RegionSize) + { + /* reallocate memory area */ + Status = NtAllocateVirtualMemory(NtCurrentProcess(), + (VOID**)&new_env, + 0, + &new_size, + MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + if (Environment == NULL) + { + RtlReleasePebLock(); + } + return(Status); + } + + if (env) + { + memmove(new_env, + env, + (hole - env) * sizeof(WCHAR)); + hole = new_env + (hole - env); + } + else + { + /* absolutely new environment */ + tail = hole = new_env; + *hole = 0; + env_end = hole + 1; + } + } + } + + /* move tail */ + memmove (hole + new_len, tail, (env_end - tail) * sizeof(WCHAR)); + + if (new_env) + { + /* we reallocated environment, let's free the old one */ + if (Environment) + *Environment = new_env; + else + NtCurrentPeb()->ProcessParameters->Environment = new_env; + + if (env) + { + size = 0; + NtFreeVirtualMemory(NtCurrentProcess(), + (PVOID*)&env, + &size, + MEM_RELEASE); + } + } + + /* and now copy given stuff */ + if (f) + { + /* copy variable name and '=' character */ + memmove(hole, + Name->Buffer, + Name->Length); + hole += Name->Length / sizeof(WCHAR); + *hole++ = L'='; + } + + /* copy value */ + memmove(hole, + Value->Buffer, + Value->Length); + hole += Value->Length / sizeof(WCHAR); + *hole = 0; + } + else + { + /* remove the environment variable */ + if (f == 0) + { + memmove(head, + tail, + (env_end - tail) * sizeof(WCHAR)); + } + else + { + Status = STATUS_VARIABLE_NOT_FOUND; + } + } + + if (Environment == NULL) + { + RtlReleasePebLock(); + } + + return(Status); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlQueryEnvironmentVariable_U(PWSTR Environment, + PUNICODE_STRING Name, + PUNICODE_STRING Value) +{ + NTSTATUS Status; + PWSTR wcs; + UNICODE_STRING var; + PWSTR val; + int len; + BOOLEAN SysEnvUsed = FALSE; + + DPRINT("RtlQueryEnvironmentVariable_U Environment %p Variable %wZ Value %p\n", + Environment, Name, Value); + + if (Environment == NULL) + { + Environment = NtCurrentPeb()->ProcessParameters->Environment; + SysEnvUsed = TRUE; + } + + if (Environment == NULL) + return(STATUS_VARIABLE_NOT_FOUND); + + Value->Length = 0; + if (SysEnvUsed == TRUE) + RtlAcquirePebLock(); + + wcs = Environment; + len = Name->Length / sizeof(WCHAR); + while (*wcs) + { + var.Buffer = wcs++; + wcs = wcschr(wcs, L'='); + if (wcs == NULL) + { + wcs = var.Buffer + wcslen(var.Buffer); + } + if (*wcs) + { + var.Length = var.MaximumLength = (wcs - var.Buffer) * sizeof(WCHAR); + val = ++wcs; + wcs += wcslen(wcs); + + if (RtlEqualUnicodeString(&var, Name, TRUE)) + { + Value->Length = (wcs - val) * sizeof(WCHAR); + if (Value->Length < Value->MaximumLength) + { + memcpy(Value->Buffer, val, Value->Length + sizeof(WCHAR)); + DPRINT("Value %S\n", val); + DPRINT("Return STATUS_SUCCESS\n"); + Status = STATUS_SUCCESS; + } + else + { + DPRINT("Return STATUS_BUFFER_TOO_SMALL\n"); + Status = STATUS_BUFFER_TOO_SMALL; + } + + if (SysEnvUsed == TRUE) + RtlReleasePebLock(); + + return(Status); + } + } + wcs++; + } + + if (SysEnvUsed == TRUE) + RtlReleasePebLock(); + + DPRINT("Return STATUS_VARIABLE_NOT_FOUND\n"); + return(STATUS_VARIABLE_NOT_FOUND); +} + +/* EOF */ diff --git a/reactos/lib/rtl/error.c b/reactos/lib/rtl/error.c new file mode 100644 index 00000000000..2fadaa214b6 --- /dev/null +++ b/reactos/lib/rtl/error.c @@ -0,0 +1,992 @@ +/* $Id: error.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PURPOSE: Rtl error functions + * FILE: lib/rtl/error.c + * PROGRAMER: Eric Kohl + * REVISION HISTORY: + * 22/07/99: Added RtlNtStatusToDosError. + * 1999-11-30: Added RtlNtStatusToPsxErrno. + * 1999-12-18: STDCALL RtlNtStatusToDosError + */ + +/* + * Partially taken from WINE, original copyright: + * + * Copyright 2000 Alexandre Julliard + */ + +/* INCLUDES *****************************************************************/ + +#include +#include + +#define NDEBUG +#include + +#ifndef HIWORD +#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF)) +#endif +#ifndef LOWORD +#define LOWORD(l) ((WORD)(l)) +#endif + +/* TYPES *******************************************************************/ + +typedef struct _ERROR_TABLE +{ + ULONG Start; + ULONG End; + const WORD *Table; +} +ERROR_TABLE, *PERROR_TABLE; + + +/* FUNCTIONS ***************************************************************/ + +static const WORD table_00000103[11] = + { + ERROR_IO_PENDING, /* 00000103 (STATUS_PENDING) */ + ERROR_MR_MID_NOT_FOUND, /* 00000104 (STATUS_REPARSE) */ + ERROR_MORE_DATA, /* 00000105 (STATUS_MORE_ENTRIES) */ + ERROR_NOT_ALL_ASSIGNED, /* 00000106 (STATUS_NOT_ALL_ASSIGNED) */ + ERROR_SOME_NOT_MAPPED, /* 00000107 (STATUS_SOME_NOT_MAPPED) */ + ERROR_MR_MID_NOT_FOUND, /* 00000108 (STATUS_OPLOCK_BREAK_IN_PROCESS) */ + ERROR_MR_MID_NOT_FOUND, /* 00000109 (STATUS_VOLUME_MOUNTED) */ + ERROR_MR_MID_NOT_FOUND, /* 0000010a (STATUS_RXACT_COMMITTED) */ + ERROR_MR_MID_NOT_FOUND, /* 0000010b (STATUS_NOTIFY_CLEANUP) */ + ERROR_NOTIFY_ENUM_DIR, /* 0000010c (STATUS_NOTIFY_ENUM_DIR) */ + ERROR_NO_QUOTAS_FOR_ACCOUNT /* 0000010d (STATUS_NO_QUOTAS_FOR_ACCOUNT) */ + // /* 0000010e (STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED) */ + }; + +static const WORD table_40000002[12] = + { + ERROR_INVALID_PARAMETER, /* 40000002 */ + ERROR_MR_MID_NOT_FOUND, /* 40000003 */ + ERROR_MR_MID_NOT_FOUND, /* 40000004 */ + ERROR_MR_MID_NOT_FOUND, /* 40000005 */ + ERROR_LOCAL_USER_SESSION_KEY, /* 40000006 (STATUS_LOCAL_USER_SESSION_KEY) */ + ERROR_MR_MID_NOT_FOUND, /* 40000007 */ + ERROR_MORE_WRITES, /* 40000008 (STATUS_SERIAL_MORE_WRITES) */ + ERROR_REGISTRY_RECOVERED, /* 40000009 (STATUS_REGISTRY_RECOVERED) */ + ERROR_MR_MID_NOT_FOUND, /* 4000000a */ + ERROR_MR_MID_NOT_FOUND, /* 4000000b */ + ERROR_COUNTER_TIMEOUT, /* 4000000c (STATUS_SERIAL_COUNTER_TIMEOUT) */ + ERROR_NULL_LM_PASSWORD /* 4000000d (STATUS_NULL_LM_PASSWORD) */ + }; + +static const WORD table_40020056[1] = + { + RPC_S_UUID_LOCAL_ONLY /* 40020056 */ + }; + +static const WORD table_400200af[1] = + { + RPC_S_SEND_INCOMPLETE /* 400200af */ + }; + +static const WORD table_80000001[38] = + { + 0, /* 80000001 (STATUS_GUARD_PAGE_VIOLATION) */ + ERROR_NOACCESS, /* 80000002 (STATUS_DATATYPE_MISALIGNMENT) */ + 0, /* 80000003 (STATUS_BREAKPOINT) */ + 0, /* 80000004 (STATUS_SINGLE_STEP) */ + ERROR_MORE_DATA, /* 80000005 (STATUS_BUFFER_OVERFLOW) */ + ERROR_NO_MORE_FILES, /* 80000006 (STATUS_NO_MORE_FILES) */ + ERROR_MR_MID_NOT_FOUND, /* 80000007 (STATUS_WAKE_SYSTEM_DEBUGGER) */ + ERROR_MR_MID_NOT_FOUND, /* 80000008 */ + ERROR_MR_MID_NOT_FOUND, /* 80000009 */ + ERROR_MR_MID_NOT_FOUND, /* 8000000a (STATUS_HANDLES_CLOSED) */ + ERROR_NO_INHERITANCE, /* 8000000b (STATUS_NO_INHERITANCE) */ + ERROR_MR_MID_NOT_FOUND, /* 8000000c (STATUS_GUID_SUBSTITUTION_MADE) */ + ERROR_PARTIAL_COPY, /* 8000000d (STATUS_PARTIAL_COPY) */ + ERROR_OUT_OF_PAPER, /* 8000000e (STATUS_DEVICE_PAPER_EMPTY) */ + ERROR_NOT_READY, /* 8000000f (STATUS_DEVICE_POWERED_OFF) */ + ERROR_NOT_READY, /* 80000010 (STATUS_DEVICE_OFF_LINE) */ + ERROR_BUSY, /* 80000011 (STATUS_DEVICE_BUSY) */ + ERROR_NO_MORE_ITEMS, /* 80000012 (STATUS_NO_MORE_EAS) */ + ERROR_INVALID_EA_NAME, /* 80000013 (STATUS_INVALID_EA_NAME) */ + ERROR_EA_LIST_INCONSISTENT, /* 80000014 (STATUS_EA_LIST_INCONSISTENT) */ + ERROR_EA_LIST_INCONSISTENT, /* 80000015 (STATUS_INVALID_EA_FLAG) */ + ERROR_MEDIA_CHANGED, /* 80000016 (STATUS_VERIFY_REQUIRED) */ + ERROR_MR_MID_NOT_FOUND, /* 80000017 (STATUS_EXTRANEOUS_INFORMATION) */ + ERROR_MR_MID_NOT_FOUND, /* 80000018 (STATUS_RXACT_COMMIT_NECESSARY) */ + ERROR_MR_MID_NOT_FOUND, /* 80000019 */ + ERROR_NO_MORE_ITEMS, /* 8000001a (STATUS_NO_MORE_ENTRIES) */ + ERROR_FILEMARK_DETECTED, /* 8000001b (STATUS_FILEMARK_DETECTED) */ + ERROR_MEDIA_CHANGED, /* 8000001c (STATUS_MEDIA_CHANGED) */ + ERROR_BUS_RESET, /* 8000001d (STATUS_BUS_RESET) */ + ERROR_END_OF_MEDIA, /* 8000001e (STATUS_END_OF_MEDIA) */ + ERROR_BEGINNING_OF_MEDIA, /* 8000001f (STATUS_BEGINNING_OF_MEDIA) */ + ERROR_MR_MID_NOT_FOUND, /* 80000020 (STATUS_MEDIA_CHECK) */ + ERROR_SETMARK_DETECTED, /* 80000021 (STATUS_SETMARK_DETECTED) */ + ERROR_NO_DATA_DETECTED, /* 80000022 (STATUS_NO_DATA_DETECTED) */ + ERROR_MR_MID_NOT_FOUND, /* 80000023 (STATUS_REDIRECTOR_HAS_OPEN_HANDLES) */ + ERROR_MR_MID_NOT_FOUND, /* 80000024 (STATUS_SERVER_HAS_OPEN_HANDLES) */ + ERROR_ACTIVE_CONNECTIONS, /* 80000025 (STATUS_ALREADY_DISCONNECTED) */ + ERROR_MR_MID_NOT_FOUND /* 80000026 (STATUS_LONGJUMP) */ + }; + +static const WORD table_80090300[23] = + { + ERROR_NO_SYSTEM_RESOURCES, /* 80090300 */ + ERROR_INVALID_HANDLE, /* 80090301 */ + ERROR_INVALID_FUNCTION, /* 80090302 */ + ERROR_BAD_NETPATH, /* 80090303 */ + ERROR_INTERNAL_ERROR, /* 80090304 */ + ERROR_NO_SUCH_PACKAGE, /* 80090305 */ + ERROR_NOT_OWNER, /* 80090306 */ + ERROR_NO_SUCH_PACKAGE, /* 80090307 */ + ERROR_INVALID_PARAMETER, /* 80090308 */ + ERROR_INVALID_PARAMETER, /* 80090309 */ + ERROR_NOT_SUPPORTED, /* 8009030a */ + ERROR_CANNOT_IMPERSONATE, /* 8009030b */ + ERROR_LOGON_FAILURE, /* 8009030c */ + ERROR_INVALID_PARAMETER, /* 8009030d */ + ERROR_NO_SUCH_LOGON_SESSION, /* 8009030e */ + ERROR_ACCESS_DENIED, /* 8009030f */ + ERROR_ACCESS_DENIED, /* 80090310 */ + ERROR_NO_LOGON_SERVERS, /* 80090311 */ + ERROR_MR_MID_NOT_FOUND, /* 80090312 */ + ERROR_MR_MID_NOT_FOUND, /* 80090313 */ + ERROR_MR_MID_NOT_FOUND, /* 80090314 */ + ERROR_MR_MID_NOT_FOUND, /* 80090315 */ + ERROR_NO_SUCH_PACKAGE /* 80090316 */ + }; + +static const WORD table_c0000001[411] = + { + ERROR_GEN_FAILURE, /* c0000001 (STATUS_UNSUCCESSFUL) */ + ERROR_INVALID_FUNCTION, /* c0000002 (STATUS_NOT_IMPLEMENTED) */ + ERROR_INVALID_PARAMETER, /* c0000003 (STATUS_INVALID_INFO_CLASS) */ + ERROR_BAD_LENGTH, /* c0000004 (STATUS_INFO_LENGTH_MISMATCH) */ + ERROR_NOACCESS, /* c0000005 (STATUS_ACCESS_VIOLATION) */ + ERROR_SWAPERROR, /* c0000006 (STATUS_IN_PAGE_ERROR) */ + ERROR_PAGEFILE_QUOTA, /* c0000007 (STATUS_PAGEFILE_QUOTA) */ + ERROR_INVALID_HANDLE, /* c0000008 (STATUS_INVALID_HANDLE) */ + ERROR_STACK_OVERFLOW, /* c0000009 (STATUS_BAD_INITIAL_STACK) */ + ERROR_BAD_EXE_FORMAT, /* c000000a (STATUS_BAD_INITIAL_PC) */ + ERROR_INVALID_PARAMETER, /* c000000b (STATUS_INVALID_CID) */ + ERROR_MR_MID_NOT_FOUND, /* c000000c (STATUS_TIMER_NOT_CANCELED) */ + ERROR_INVALID_PARAMETER, /* c000000d (STATUS_INVALID_PARAMETER) */ + ERROR_FILE_NOT_FOUND, /* c000000e (STATUS_NO_SUCH_DEVICE) */ + ERROR_FILE_NOT_FOUND, /* c000000f (STATUS_NO_SUCH_FILE) */ + ERROR_INVALID_FUNCTION, /* c0000010 (STATUS_INVALID_DEVICE_REQUEST) */ + ERROR_HANDLE_EOF, /* c0000011 (STATUS_END_OF_FILE) */ + ERROR_WRONG_DISK, /* c0000012 (STATUS_WRONG_VOLUME) */ + ERROR_NOT_READY, /* c0000013 (STATUS_NO_MEDIA_IN_DEVICE) */ + ERROR_UNRECOGNIZED_MEDIA, /* c0000014 (STATUS_UNRECOGNIZED_MEDIA) */ + ERROR_SECTOR_NOT_FOUND, /* c0000015 (STATUS_NONEXISTENT_SECTOR) */ + ERROR_MORE_DATA, /* c0000016 (STATUS_MORE_PROCESSING_REQUIRED) */ + ERROR_NOT_ENOUGH_MEMORY, /* c0000017 (STATUS_NO_MEMORY) */ + ERROR_INVALID_ADDRESS, /* c0000018 (STATUS_CONFLICTING_ADDRESSES) */ + ERROR_INVALID_ADDRESS, /* c0000019 (STATUS_NOT_MAPPED_VIEW) */ + ERROR_INVALID_PARAMETER, /* c000001a (STATUS_UNABLE_TO_FREE_VM) */ + ERROR_INVALID_PARAMETER, /* c000001b (STATUS_UNABLE_TO_DELETE_SECTION) */ + ERROR_INVALID_FUNCTION, /* c000001c (STATUS_INVALID_SYSTEM_SERVICE) */ + 0, /* c000001d (STATUS_ILLEGAL_INSTRUCTION) */ + ERROR_ACCESS_DENIED, /* c000001e (STATUS_INVALID_LOCK_SEQUENCE) */ + ERROR_ACCESS_DENIED, /* c000001f (STATUS_INVALID_VIEW_SIZE) */ + ERROR_BAD_EXE_FORMAT, /* c0000020 (STATUS_INVALID_FILE_FOR_SECTION) */ + ERROR_ACCESS_DENIED, /* c0000021 (STATUS_ALREADY_COMMITTED) */ + ERROR_ACCESS_DENIED, /* c0000022 (STATUS_ACCESS_DENIED) */ + ERROR_INSUFFICIENT_BUFFER, /* c0000023 (STATUS_BUFFER_TOO_SMALL) */ + ERROR_INVALID_HANDLE, /* c0000024 (STATUS_OBJECT_TYPE_MISMATCH) */ + 0, /* c0000025 (STATUS_NONCONTINUABLE_EXCEPTION) */ + 0, /* c0000026 (STATUS_INVALID_DISPOSITION) */ + ERROR_MR_MID_NOT_FOUND, /* c0000027 (STATUS_UNWIND) */ + ERROR_MR_MID_NOT_FOUND, /* c0000028 (STATUS_BAD_STACK) */ + ERROR_MR_MID_NOT_FOUND, /* c0000029 (STATUS_INVALID_UNWIND_TARGET) */ + ERROR_NOT_LOCKED, /* c000002a (STATUS_NOT_LOCKED) */ + 0, /* c000002b (STATUS_PARITY_ERROR) */ + ERROR_INVALID_ADDRESS, /* c000002c (STATUS_UNABLE_TO_DECOMMIT_VM) */ + ERROR_INVALID_ADDRESS, /* c000002d (STATUS_NOT_COMMITTED) */ + ERROR_MR_MID_NOT_FOUND, /* c000002e (STATUS_INVALID_PORT_ATTRIBUTES) */ + ERROR_MR_MID_NOT_FOUND, /* c000002f (STATUS_PORT_MESSAGE_TOO_LONG) */ + ERROR_INVALID_PARAMETER, /* c0000030 (STATUS_INVALID_PARAMETER_MIX) */ + ERROR_MR_MID_NOT_FOUND, /* c0000031 (STATUS_INVALID_QUOTA_LOWER) */ + ERROR_DISK_CORRUPT, /* c0000032 (STATUS_DISK_CORRUPT_ERROR) */ + ERROR_INVALID_NAME, /* c0000033 (STATUS_OBJECT_NAME_INVALID) */ + ERROR_FILE_NOT_FOUND, /* c0000034 (STATUS_OBJECT_NAME_NOT_FOUND) */ + ERROR_ALREADY_EXISTS, /* c0000035 (STATUS_OBJECT_NAME_COLLISION) */ + ERROR_MR_MID_NOT_FOUND, /* c0000036 */ + ERROR_INVALID_HANDLE, /* c0000037 (STATUS_PORT_DISCONNECTED) */ + ERROR_MR_MID_NOT_FOUND, /* c0000038 (STATUS_DEVICE_ALREADY_ATTACHED) */ + ERROR_BAD_PATHNAME, /* c0000039 (STATUS_OBJECT_PATH_INVALID) */ + ERROR_PATH_NOT_FOUND, /* c000003a (STATUS_OBJECT_PATH_NOT_FOUND) */ + ERROR_BAD_PATHNAME, /* c000003b (STATUS_PATH_SYNTAX_BAD) */ + ERROR_IO_DEVICE, /* c000003c (STATUS_DATA_OVERRUN) */ + ERROR_IO_DEVICE, /* c000003d (STATUS_DATA_LATE_ERROR) */ + ERROR_CRC, /* c000003e (STATUS_DATA_ERROR) */ + ERROR_CRC, /* c000003f (STATUS_CRC_ERROR) */ + ERROR_NOT_ENOUGH_MEMORY, /* c0000040 (STATUS_SECTION_TOO_BIG) */ + ERROR_ACCESS_DENIED, /* c0000041 (STATUS_PORT_CONNECTION_REFUSED) */ + ERROR_INVALID_HANDLE, /* c0000042 (STATUS_INVALID_PORT_HANDLE) */ + ERROR_SHARING_VIOLATION, /* c0000043 (STATUS_SHARING_VIOLATION) */ + ERROR_NOT_ENOUGH_QUOTA, /* c0000044 (STATUS_QUOTA_EXCEEDED) */ + ERROR_INVALID_PARAMETER, /* c0000045 (STATUS_INVALID_PAGE_PROTECTION) */ + ERROR_NOT_OWNER, /* c0000046 (STATUS_MUTANT_NOT_OWNED) */ + ERROR_TOO_MANY_POSTS, /* c0000047 (STATUS_SEMAPHORE_LIMIT_EXCEEDED) */ + ERROR_INVALID_PARAMETER, /* c0000048 (STATUS_PORT_ALREADY_SET) */ + ERROR_INVALID_PARAMETER, /* c0000049 (STATUS_SECTION_NOT_IMAGE) */ + ERROR_SIGNAL_REFUSED, /* c000004a (STATUS_SUSPEND_COUNT_EXCEEDED) */ + ERROR_ACCESS_DENIED, /* c000004b (STATUS_THREAD_IS_TERMINATING) */ + ERROR_INVALID_PARAMETER, /* c000004c (STATUS_BAD_WORKING_SET_LIMIT) */ + ERROR_INVALID_PARAMETER, /* c000004d (STATUS_INCOMPATIBLE_FILE_MAP) */ + ERROR_INVALID_PARAMETER, /* c000004e (STATUS_SECTION_PROTECTION) */ + ERROR_MR_MID_NOT_FOUND, /* c000004f (STATUS_EAS_NOT_SUPPORTED) */ + ERROR_EA_LIST_INCONSISTENT, /* c0000050 (STATUS_EA_TOO_LARGE) */ + ERROR_FILE_CORRUPT, /* c0000051 (STATUS_NONEXISTENT_EA_ENTRY) */ + ERROR_FILE_CORRUPT, /* c0000052 (STATUS_NO_EAS_ON_FILE) */ + ERROR_FILE_CORRUPT, /* c0000053 (STATUS_EA_CORRUPT_ERROR) */ + ERROR_LOCK_VIOLATION, /* c0000054 (STATUS_LOCK_NOT_GRANTED) */ + ERROR_LOCK_VIOLATION, /* c0000055 (STATUS_FILE_LOCK_CONFLICT) */ + ERROR_ACCESS_DENIED, /* c0000056 (STATUS_DELETE_PENDING) */ + ERROR_NOT_SUPPORTED, /* c0000057 (STATUS_CTL_FILE_NOT_SUPPORTED) */ + ERROR_UNKNOWN_REVISION, /* c0000058 (STATUS_UNKNOWN_REVISION) */ + ERROR_REVISION_MISMATCH, /* c0000059 (STATUS_REVISION_MISMATCH) */ + ERROR_INVALID_OWNER, /* c000005a (STATUS_INVALID_OWNER) */ + ERROR_INVALID_PRIMARY_GROUP, /* c000005b (STATUS_INVALID_PRIMARY_GROUP) */ + ERROR_NO_IMPERSONATION_TOKEN, /* c000005c (STATUS_NO_IMPERSONATION_TOKEN) */ + ERROR_CANT_DISABLE_MANDATORY, /* c000005d (STATUS_CANT_DISABLE_MANDATORY) */ + ERROR_NO_LOGON_SERVERS, /* c000005e (STATUS_NO_LOGON_SERVERS) */ + ERROR_NO_SUCH_LOGON_SESSION, /* c000005f (STATUS_NO_SUCH_LOGON_SESSION) */ + ERROR_NO_SUCH_PRIVILEGE, /* c0000060 (STATUS_NO_SUCH_PRIVILEGE) */ + ERROR_PRIVILEGE_NOT_HELD, /* c0000061 (STATUS_PRIVILEGE_NOT_HELD) */ + ERROR_INVALID_ACCOUNT_NAME, /* c0000062 (STATUS_INVALID_ACCOUNT_NAME) */ + ERROR_USER_EXISTS, /* c0000063 (STATUS_USER_EXISTS) */ + ERROR_NO_SUCH_USER, /* c0000064 (STATUS_NO_SUCH_USER) */ + ERROR_GROUP_EXISTS, /* c0000065 (STATUS_GROUP_EXISTS) */ + ERROR_NO_SUCH_GROUP, /* c0000066 (STATUS_NO_SUCH_GROUP) */ + ERROR_MEMBER_IN_GROUP, /* c0000067 (STATUS_MEMBER_IN_GROUP) */ + ERROR_MEMBER_NOT_IN_GROUP, /* c0000068 (STATUS_MEMBER_NOT_IN_GROUP) */ + ERROR_LAST_ADMIN, /* c0000069 (STATUS_LAST_ADMIN) */ + ERROR_INVALID_PASSWORD, /* c000006a (STATUS_WRONG_PASSWORD) */ + ERROR_ILL_FORMED_PASSWORD, /* c000006b (STATUS_ILL_FORMED_PASSWORD) */ + ERROR_PASSWORD_RESTRICTION, /* c000006c (STATUS_PASSWORD_RESTRICTION) */ + ERROR_LOGON_FAILURE, /* c000006d (STATUS_LOGON_FAILURE) */ + ERROR_ACCOUNT_RESTRICTION, /* c000006e (STATUS_ACCOUNT_RESTRICTION) */ + ERROR_INVALID_LOGON_HOURS, /* c000006f (STATUS_INVALID_LOGON_HOURS) */ + ERROR_INVALID_WORKSTATION, /* c0000070 (STATUS_INVALID_WORKSTATION) */ + ERROR_PASSWORD_EXPIRED, /* c0000071 (STATUS_PASSWORD_EXPIRED) */ + ERROR_ACCOUNT_DISABLED, /* c0000072 (STATUS_ACCOUNT_DISABLED) */ + ERROR_NONE_MAPPED, /* c0000073 (STATUS_NONE_MAPPED) */ + ERROR_TOO_MANY_LUIDS_REQUESTED, /* c0000074 (STATUS_TOO_MANY_LUIDS_REQUESTED) */ + ERROR_LUIDS_EXHAUSTED, /* c0000075 (STATUS_LUIDS_EXHAUSTED) */ + ERROR_INVALID_SUB_AUTHORITY, /* c0000076 (STATUS_INVALID_SUB_AUTHORITY) */ + ERROR_INVALID_ACL, /* c0000077 (STATUS_INVALID_ACL) */ + ERROR_INVALID_SID, /* c0000078 (STATUS_INVALID_SID) */ + ERROR_INVALID_SECURITY_DESCR, /* c0000079 (STATUS_INVALID_SECURITY_DESCR) */ + ERROR_PROC_NOT_FOUND, /* c000007a (STATUS_PROCEDURE_NOT_FOUND) */ + ERROR_BAD_EXE_FORMAT, /* c000007b (STATUS_INVALID_IMAGE_FORMAT) */ + ERROR_NO_TOKEN, /* c000007c (STATUS_NO_TOKEN) */ + ERROR_BAD_INHERITANCE_ACL, /* c000007d (STATUS_BAD_INHERITANCE_ACL) */ + ERROR_NOT_LOCKED, /* c000007e (STATUS_RANGE_NOT_LOCKED) */ + ERROR_DISK_FULL, /* c000007f (STATUS_DISK_FULL) */ + ERROR_SERVER_DISABLED, /* c0000080 (STATUS_SERVER_DISABLED) */ + ERROR_SERVER_NOT_DISABLED, /* c0000081 (STATUS_SERVER_NOT_DISABLED) */ + ERROR_TOO_MANY_NAMES, /* c0000082 (STATUS_TOO_MANY_GUIDS_REQUESTED) */ + ERROR_NO_MORE_ITEMS, /* c0000083 (STATUS_GUIDS_EXHAUSTED) */ + ERROR_INVALID_ID_AUTHORITY, /* c0000084 (STATUS_INVALID_ID_AUTHORITY) */ + ERROR_NO_MORE_ITEMS, /* c0000085 (STATUS_AGENTS_EXHAUSTED) */ + ERROR_LABEL_TOO_LONG, /* c0000086 (STATUS_INVALID_VOLUME_LABEL) */ + ERROR_OUTOFMEMORY, /* c0000087 (STATUS_SECTION_NOT_EXTENDED) */ + ERROR_INVALID_ADDRESS, /* c0000088 (STATUS_NOT_MAPPED_DATA) */ + ERROR_RESOURCE_DATA_NOT_FOUND, /* c0000089 (STATUS_RESOURCE_DATA_NOT_FOUND) */ + ERROR_RESOURCE_TYPE_NOT_FOUND, /* c000008a (STATUS_RESOURCE_TYPE_NOT_FOUND) */ + ERROR_RESOURCE_NAME_NOT_FOUND, /* c000008b (STATUS_RESOURCE_NAME_NOT_FOUND) */ + 0, /* c000008c (STATUS_ARRAY_BOUNDS_EXCEEDED) */ + 0, /* c000008d (STATUS_FLOAT_DENORMAL_OPERAND) */ + 0, /* c000008e (STATUS_FLOAT_DIVIDE_BY_ZERO) */ + 0, /* c000008f (STATUS_FLOAT_INEXACT_RESULT) */ + 0, /* c0000090 (STATUS_FLOAT_INVALID_OPERATION) */ + 0, /* c0000091 (STATUS_FLOAT_OVERFLOW) */ + 0, /* c0000092 (STATUS_FLOAT_STACK_CHECK) */ + 0, /* c0000093 (STATUS_FLOAT_UNDERFLOW) */ + 0, /* c0000094 (STATUS_INTEGER_DIVIDE_BY_ZERO) */ + ERROR_ARITHMETIC_OVERFLOW, /* c0000095 (STATUS_INTEGER_OVERFLOW) */ + 0, /* c0000096 (STATUS_PRIVILEGED_INSTRUCTION) */ + ERROR_NOT_ENOUGH_MEMORY, /* c0000097 (STATUS_TOO_MANY_PAGING_FILES) */ + ERROR_FILE_INVALID, /* c0000098 (STATUS_FILE_INVALID) */ + ERROR_ALLOTTED_SPACE_EXCEEDED, /* c0000099 (STATUS_ALLOTTED_SPACE_EXCEEDED) */ + ERROR_NO_SYSTEM_RESOURCES, /* c000009a (STATUS_INSUFFICIENT_RESOURCES) */ + ERROR_PATH_NOT_FOUND, /* c000009b (STATUS_DFS_EXIT_PATH_FOUND) */ + ERROR_CRC, /* c000009c (STATUS_DEVICE_DATA_ERROR) */ + ERROR_NOT_READY, /* c000009d (STATUS_DEVICE_NOT_CONNECTED) */ + ERROR_NOT_READY, /* c000009e (STATUS_DEVICE_POWER_FAILURE) */ + ERROR_INVALID_ADDRESS, /* c000009f (STATUS_FREE_VM_NOT_AT_BASE) */ + ERROR_INVALID_ADDRESS, /* c00000a0 (STATUS_MEMORY_NOT_ALLOCATED) */ + ERROR_WORKING_SET_QUOTA, /* c00000a1 (STATUS_WORKING_SET_QUOTA) */ + ERROR_WRITE_PROTECT, /* c00000a2 (STATUS_MEDIA_WRITE_PROTECTED) */ + ERROR_NOT_READY, /* c00000a3 (STATUS_DEVICE_NOT_READY) */ + ERROR_INVALID_GROUP_ATTRIBUTES, /* c00000a4 (STATUS_INVALID_GROUP_ATTRIBUTES) */ + ERROR_BAD_IMPERSONATION_LEVEL, /* c00000a5 (STATUS_BAD_IMPERSONATION_LEVEL) */ + ERROR_CANT_OPEN_ANONYMOUS, /* c00000a6 (STATUS_CANT_OPEN_ANONYMOUS) */ + ERROR_BAD_VALIDATION_CLASS, /* c00000a7 (STATUS_BAD_VALIDATION_CLASS) */ + ERROR_BAD_TOKEN_TYPE, /* c00000a8 (STATUS_BAD_TOKEN_TYPE)*/ + ERROR_MR_MID_NOT_FOUND, /* c00000a9 (STATUS_BAD_MASTER_BOOT_RECORD) */ + ERROR_MR_MID_NOT_FOUND, /* c00000aa (STATUS_INSTRUCTION_MISALIGNMENT) */ + ERROR_PIPE_BUSY, /* c00000ab (STATUS_INSTANCE_NOT_AVAILABLE) */ + ERROR_PIPE_BUSY, /* c00000ac (STATUS_PIPE_NOT_AVAILABLE) */ + ERROR_BAD_PIPE, /* c00000ad (STATUS_INVALID_PIPE_STATE) */ + ERROR_PIPE_BUSY, /* c00000ae (STATUS_PIPE_BUSY) */ + ERROR_INVALID_FUNCTION, /* c00000af (STATUS_ILLEGAL_FUNCTION) */ + ERROR_PIPE_NOT_CONNECTED, /* c00000b0 (STATUS_PIPE_DISCONNECTED) */ + ERROR_NO_DATA, /* c00000b1 (STATUS_PIPE_CLOSING) */ + ERROR_PIPE_CONNECTED, /* c00000b2 (STATUS_PIPE_CONNECTED) */ + ERROR_PIPE_LISTENING, /* c00000b3 (STATUS_PIPE_LISTENING) */ + ERROR_BAD_PIPE, /* c00000b4 (STATUS_INVALID_READ_MODE) */ + ERROR_SEM_TIMEOUT, /* c00000b5 (STATUS_IO_TIMEOUT) */ + ERROR_HANDLE_EOF, /* c00000b6 (STATUS_FILE_FORCED_CLOSED) */ + ERROR_MR_MID_NOT_FOUND, /* c00000b7 (STATUS_PROFILING_NOT_STARTED) */ + ERROR_MR_MID_NOT_FOUND, /* c00000b8 (STATUS_PROFILING_NOT_STOPPED) */ + ERROR_MR_MID_NOT_FOUND, /* c00000b9 (STATUS_COULD_NOT_INTERPRET) */ + ERROR_ACCESS_DENIED, /* c00000ba (STATUS_FILE_IS_A_DIRECTORY) */ + ERROR_NOT_SUPPORTED, /* c00000bb (STATUS_NOT_SUPPORTED) */ + ERROR_REM_NOT_LIST, /* c00000bc (STATUS_REMOTE_NOT_LISTENING) */ + ERROR_DUP_NAME, /* c00000bd (STATUS_DUPLICATE_NAME) */ + ERROR_BAD_NETPATH, /* c00000be (STATUS_BAD_NETWORK_PATH) */ + ERROR_NETWORK_BUSY, /* c00000bf (STATUS_NETWORK_BUSY) */ + ERROR_DEV_NOT_EXIST, /* c00000c0 (STATUS_DEVICE_DOES_NOT_EXIST) */ + ERROR_TOO_MANY_CMDS, /* c00000c1 (STATUS_TOO_MANY_COMMANDS) */ + ERROR_ADAP_HDW_ERR, /* c00000c2 (STATUS_ADAPTER_HARDWARE_ERROR) */ + ERROR_BAD_NET_RESP, /* c00000c3 (STATUS_INVALID_NETWORK_RESPONSE) */ + ERROR_UNEXP_NET_ERR, /* c00000c4 (STATUS_UNEXPECTED_NETWORK_ERROR) */ + ERROR_BAD_REM_ADAP, /* c00000c5 (STATUS_BAD_REMOTE_ADAPTER) */ + ERROR_PRINTQ_FULL, /* c00000c6 (STATUS_PRINT_QUEUE_FULL) */ + ERROR_NO_SPOOL_SPACE, /* c00000c7 (STATUS_NO_SPOOL_SPACE) */ + ERROR_PRINT_CANCELLED, /* c00000c8 (STATUS_PRINT_CANCELLED) */ + ERROR_NETNAME_DELETED, /* c00000c9 (STATUS_NETWORK_NAME_DELETED) */ + ERROR_NETWORK_ACCESS_DENIED, /* c00000ca (STATUS_NETWORK_ACCESS_DENIED) */ + ERROR_BAD_DEV_TYPE, /* c00000cb (STATUS_BAD_DEVICE_TYPE) */ + ERROR_BAD_NET_NAME, /* c00000cc (STATUS_BAD_NETWORK_NAME) */ + ERROR_TOO_MANY_NAMES, /* c00000cd (STATUS_TOO_MANY_NAMES) */ + ERROR_TOO_MANY_SESS, /* c00000ce (STATUS_TOO_MANY_SESSIONS) */ + ERROR_SHARING_PAUSED, /* c00000cf (STATUS_SHARING_PAUSED) */ + ERROR_REQ_NOT_ACCEP, /* c00000d0 (STATUS_REQUEST_NOT_ACCEPTED) */ + ERROR_REDIR_PAUSED, /* c00000d1 (STATUS_REDIRECTOR_PAUSED) */ + ERROR_NET_WRITE_FAULT, /* c00000d2 (STATUS_NET_WRITE_FAULT) */ + ERROR_MR_MID_NOT_FOUND, /* c00000d3 (STATUS_PROFILING_AT_LIMIT) */ + ERROR_NOT_SAME_DEVICE, /* c00000d4 (STATUS_NOT_SAME_DEVICE) */ + ERROR_MR_MID_NOT_FOUND, /* c00000d5 (STATUS_FILE_RENAMED) */ + ERROR_VC_DISCONNECTED, /* c00000d6 (STATUS_VIRTUAL_CIRCUIT_CLOSED) */ + ERROR_NO_SECURITY_ON_OBJECT, /* c00000d7 (STATUS_NO_SECURITY_ON_OBJECT) */ + ERROR_MR_MID_NOT_FOUND, /* c00000d8 (STATUS_CANT_WAIT) */ + ERROR_NO_DATA, /* c00000d9 (STATUS_PIPE_EMPTY) */ + ERROR_CANT_ACCESS_DOMAIN_INFO, /* c00000da (STATUS_CANT_ACCESS_DOMAIN_INFO) */ + ERROR_MR_MID_NOT_FOUND, /* c00000db (STATUS_CANT_TERMINATE_SELF) */ + ERROR_INVALID_SERVER_STATE, /* c00000dc (STATUS_INVALID_SERVER_STATE) */ + ERROR_INVALID_DOMAIN_STATE, /* c00000dd (STATUS_INVALID_DOMAIN_STATE) */ + ERROR_INVALID_DOMAIN_ROLE, /* c00000de (STATUS_INVALID_DOMAIN_ROLE) */ + ERROR_NO_SUCH_DOMAIN, /* c00000df (STATUS_NO_SUCH_DOMAIN) */ + ERROR_DOMAIN_EXISTS, /* c00000e0 (STATUS_DOMAIN_EXISTS) */ + ERROR_DOMAIN_LIMIT_EXCEEDED, /* c00000e1 (STATUS_DOMAIN_LIMIT_EXCEEDED) */ + ERROR_MR_MID_NOT_FOUND, /* c00000e2 (STATUS_OPLOCK_NOT_GRANTED) */ + ERROR_MR_MID_NOT_FOUND, /* c00000e3 (STATUS_INVALID_OPLOCK_PROTOCOL) */ + ERROR_INTERNAL_DB_CORRUPTION, /* c00000e4 (STATUS_INTERNAL_DB_CORRUPTION) */ + ERROR_INTERNAL_ERROR, /* c00000e5 (STATUS_INTERNAL_ERROR) */ + ERROR_GENERIC_NOT_MAPPED, /* c00000e6 (STATUS_GENERIC_NOT_MAPPED) */ + ERROR_BAD_DESCRIPTOR_FORMAT, /* c00000e7 (STATUS_BAD_DESCRIPTOR_FORMAT) */ + ERROR_INVALID_USER_BUFFER, /* c00000e8 (STATUS_INVALID_USER_BUFFER) */ + ERROR_MR_MID_NOT_FOUND, /* c00000e9 (STATUS_UNEXPECTED_IO_ERROR) */ + ERROR_MR_MID_NOT_FOUND, /* c00000ea (STATUS_UNEXPECTED_MM_CREATE_ERR) */ + ERROR_MR_MID_NOT_FOUND, /* c00000eb (STATUS_UNEXPECTED_MM_MAP_ERROR) */ + ERROR_MR_MID_NOT_FOUND, /* c00000ec (STATUS_UNEXPECTED_MM_EXTEND_ERR) */ + ERROR_NOT_LOGON_PROCESS, /* c00000ed (STATUS_NOT_LOGON_PROCESS) */ + ERROR_LOGON_SESSION_EXISTS, /* c00000ee (STATUS_LOGON_SESSION_EXISTS) */ + ERROR_INVALID_PARAMETER, /* c00000ef (STATUS_INVALID_PARAMETER_1) */ + ERROR_INVALID_PARAMETER, /* c00000f0 (STATUS_INVALID_PARAMETER_2) */ + ERROR_INVALID_PARAMETER, /* c00000f1 (STATUS_INVALID_PARAMETER_3) */ + ERROR_INVALID_PARAMETER, /* c00000f2 (STATUS_INVALID_PARAMETER_4) */ + ERROR_INVALID_PARAMETER, /* c00000f3 (STATUS_INVALID_PARAMETER_5) */ + ERROR_INVALID_PARAMETER, /* c00000f4 (STATUS_INVALID_PARAMETER_6) */ + ERROR_INVALID_PARAMETER, /* c00000f5 (STATUS_INVALID_PARAMETER_7) */ + ERROR_INVALID_PARAMETER, /* c00000f6 (STATUS_INVALID_PARAMETER_8) */ + ERROR_INVALID_PARAMETER, /* c00000f7 (STATUS_INVALID_PARAMETER_9) */ + ERROR_INVALID_PARAMETER, /* c00000f8 (STATUS_INVALID_PARAMETER_10) */ + ERROR_INVALID_PARAMETER, /* c00000f9 (STATUS_INVALID_PARAMETER_11) */ + ERROR_INVALID_PARAMETER, /* c00000fa (STATUS_INVALID_PARAMETER_12) */ + ERROR_PATH_NOT_FOUND, /* c00000fb (STATUS_REDIRECTOR_NOT_STARTED) */ + ERROR_MR_MID_NOT_FOUND, /* c00000fc (STATUS_REDIRECTOR_STARTED) */ + ERROR_STACK_OVERFLOW, /* c00000fd (STATUS_STACK_OVERFLOW) */ + ERROR_NO_SUCH_PACKAGE, /* c00000fe (STATUS_NO_SUCH_PACKAGE) */ + ERROR_MR_MID_NOT_FOUND, /* c00000ff (STATUS_BAD_FUNCTION_TABLE) */ + ERROR_ENVVAR_NOT_FOUND, /* c0000100 (STATUS_VARIABLE_NOT_FOUND) */ + ERROR_DIR_NOT_EMPTY, /* c0000101 (STATUS_DIRECTORY_NOT_EMPTY) */ + ERROR_FILE_CORRUPT, /* c0000102 (STATUS_FILE_CORRUPT_ERROR) */ + ERROR_DIRECTORY, /* c0000103 (STATUS_NOT_A_DIRECTORY) */ + ERROR_BAD_LOGON_SESSION_STATE, /* c0000104 (STATUS_BAD_LOGON_SESSION_STATE) */ + ERROR_LOGON_SESSION_COLLISION, /* c0000105 (STATUS_LOGON_SESSION_COLLISION) */ + ERROR_FILENAME_EXCED_RANGE, /* c0000106 (STATUS_NAME_TOO_LONG) */ + ERROR_MR_MID_NOT_FOUND, /* c0000107 (STATUS_FILES_OPEN) */ + ERROR_DEVICE_IN_USE, /* c0000108 (STATUS_CONNECTION_IN_USE) */ + ERROR_MR_MID_NOT_FOUND, /* c0000109 (STATUS_MESSAGE_NOT_FOUND) */ + ERROR_ACCESS_DENIED, /* c000010a (STATUS_PROCESS_IS_TERMINATING) */ + ERROR_INVALID_LOGON_TYPE, /* c000010b (STATUS_INVALID_LOGON_TYPE) */ + ERROR_MR_MID_NOT_FOUND, /* c000010c (STATUS_NO_GUID_TRANSLATION) */ + ERROR_CANNOT_IMPERSONATE, /* c000010d (STATUS_CANNOT_IMPERSONATE) */ + ERROR_SERVICE_ALREADY_RUNNING, /* c000010e (STATUS_IMAGE_ALREADY_LOADED) */ + ERROR_MR_MID_NOT_FOUND, /* c000010f (STATUS_ABIOS_NOT_PRESENT) */ + ERROR_MR_MID_NOT_FOUND, /* c0000110 (STATUS_ABIOS_LID_NOT_EXIST) */ + ERROR_MR_MID_NOT_FOUND, /* c0000111 (STATUS_ABIOS_LID_ALREADY_OWNED) */ + ERROR_MR_MID_NOT_FOUND, /* c0000112 (STATUS_ABIOS_NOT_LID_OWNER) */ + ERROR_MR_MID_NOT_FOUND, /* c0000113 (STATUS_ABIOS_INVALID_COMMAND) */ + ERROR_MR_MID_NOT_FOUND, /* c0000114 (STATUS_ABIOS_INVALID_LID) */ + ERROR_MR_MID_NOT_FOUND, /* c0000115 (STATUS_ABIOS_SELECTOR_NOT_AVAILABLE) */ + ERROR_MR_MID_NOT_FOUND, /* c0000116 (STATUS_ABIOS_INVALID_SELECTOR) */ + ERROR_MR_MID_NOT_FOUND, /* c0000117 (STATUS_NO_LDT) */ + ERROR_MR_MID_NOT_FOUND, /* c0000118 (STATUS_INVALID_LDT_SIZE) */ + ERROR_MR_MID_NOT_FOUND, /* c0000119 (STATUS_INVALID_LDT_OFFSET) */ + ERROR_MR_MID_NOT_FOUND, /* c000011a (STATUS_INVALID_LDT_DESCRIPTOR) */ + ERROR_BAD_EXE_FORMAT, /* c000011b (STATUS_INVALID_IMAGE_NE_FORMAT) */ + ERROR_RXACT_INVALID_STATE, /* c000011c (STATUS_RXACT_INVALID_STATE) */ + ERROR_RXACT_COMMIT_FAILURE, /* c000011d (STATUS_RXACT_COMMIT_FAILURE) */ + ERROR_FILE_INVALID, /* c000011e (STATUS_MAPPED_FILE_SIZE_ZERO) */ + ERROR_TOO_MANY_OPEN_FILES, /* c000011f (STATUS_TOO_MANY_OPENED_FILES) */ + ERROR_OPERATION_ABORTED, /* c0000120 (STATUS_CANCELLED) */ + ERROR_ACCESS_DENIED, /* c0000121 (STATUS_CANNOT_DELETE) */ + ERROR_INVALID_COMPUTERNAME, /* c0000122 (STATUS_INVALID_COMPUTER_NAME) */ + ERROR_ACCESS_DENIED, /* c0000123 (STATUS_FILE_DELETED) */ + ERROR_SPECIAL_ACCOUNT, /* c0000124 (STATUS_SPECIAL_ACCOUNT) */ + ERROR_SPECIAL_GROUP, /* c0000125 (STATUS_SPECIAL_GROUP) */ + ERROR_SPECIAL_USER, /* c0000126 (STATUS_SPECIAL_USER) */ + ERROR_MEMBERS_PRIMARY_GROUP, /* c0000127 (STATUS_MEMBERS_PRIMARY_GROUP) */ + ERROR_INVALID_HANDLE, /* c0000128 (STATUS_FILE_CLOSED) */ + ERROR_MR_MID_NOT_FOUND, /* c0000129 (STATUS_TOO_MANY_THREADS) */ + ERROR_MR_MID_NOT_FOUND, /* c000012a (STATUS_THREAD_NOT_IN_PROCESS) */ + ERROR_TOKEN_ALREADY_IN_USE, /* c000012b (STATUS_TOKEN_ALREADY_IN_USE) */ + ERROR_MR_MID_NOT_FOUND, /* c000012c (STATUS_PAGEFILE_QUOTA_EXCEEDED) */ + ERROR_COMMITMENT_LIMIT, /* c000012d (STATUS_COMMITMENT_LIMIT) */ + ERROR_BAD_EXE_FORMAT, /* c000012e (STATUS_INVALID_IMAGE_LE_FORMAT) */ + ERROR_BAD_EXE_FORMAT, /* c000012f (STATUS_INVALID_IMAGE_NOT_MZ) */ + ERROR_BAD_EXE_FORMAT, /* c0000130 (STATUS_INVALID_IMAGE_PROTECT) */ + ERROR_BAD_EXE_FORMAT, /* c0000131 (STATUS_INVALID_IMAGE_WIN_16) */ + ERROR_MR_MID_NOT_FOUND, /* c0000132 (STATUS_LOGON_SERVER_CONFLICT) */ + ERROR_MR_MID_NOT_FOUND, /* c0000133 (STATUS_TIME_DIFFERENCE_AT_DC) */ + ERROR_MR_MID_NOT_FOUND, /* c0000134 (STATUS_SYNCHRONIZATION_REQUIRED) */ + ERROR_MOD_NOT_FOUND, /* c0000135 (STATUS_DLL_NOT_FOUND) */ + ERROR_MR_MID_NOT_FOUND, /* c0000136 (STATUS_OPEN_FAILED) */ + ERROR_MR_MID_NOT_FOUND, /* c0000137 (STATUS_IO_PRIVILEGE_FAILED) */ + ERROR_INVALID_ORDINAL, /* c0000138 (STATUS_ORDINAL_NOT_FOUND) */ + ERROR_PROC_NOT_FOUND, /* c0000139 (STATUS_ENTRYPOINT_NOT_FOUND) */ + ERROR_MR_MID_NOT_FOUND, /* c000013a (STATUS_CONTROL_C_EXIT) */ + ERROR_NETNAME_DELETED, /* c000013b (STATUS_LOCAL_DISCONNECT) */ + ERROR_NETNAME_DELETED, /* c000013c (STATUS_REMOTE_DISCONNECT) */ + ERROR_REM_NOT_LIST, /* c000013d (STATUS_REMOTE_RESOURCES) */ + ERROR_UNEXP_NET_ERR, /* c000013e (STATUS_LINK_FAILED) */ + ERROR_UNEXP_NET_ERR, /* c000013f (STATUS_LINK_TIMEOUT) */ + ERROR_UNEXP_NET_ERR, /* c0000140 (STATUS_INVALID_CONNECTION) */ + ERROR_UNEXP_NET_ERR, /* c0000141 (STATUS_INVALID_ADDRESS) */ + ERROR_DLL_INIT_FAILED, /* c0000142 (STATUS_DLL_INIT_FAILED) */ + ERROR_MR_MID_NOT_FOUND, /* c0000143 (STATUS_MISSING_SYSTEMFILE) */ + ERROR_MR_MID_NOT_FOUND, /* c0000144 (STATUS_UNHANDLED_EXCEPTION) */ + ERROR_MR_MID_NOT_FOUND, /* c0000145 (STATUS_APP_INIT_FAILURE) */ + ERROR_MR_MID_NOT_FOUND, /* c0000146 (STATUS_PAGEFILE_CREATE_FAILED) */ + ERROR_MR_MID_NOT_FOUND, /* c0000147 (STATUS_NO_PAGEFILE) */ + ERROR_INVALID_LEVEL, /* c0000148 (STATUS_INVALID_LEVEL) */ + ERROR_INVALID_PASSWORD, /* c0000149 (STATUS_WRONG_PASSWORD_CORE) */ + ERROR_MR_MID_NOT_FOUND, /* c000014a (STATUS_ILLEGAL_FLOAT_CONTEXT) */ + ERROR_BROKEN_PIPE, /* c000014b (STATUS_PIPE_BROKEN) */ + ERROR_BADDB, /* c000014c (STATUS_REGISTRY_CORRUPT) */ + ERROR_REGISTRY_IO_FAILED, /* c000014d (STATUS_REGISTRY_IO_FAILED) */ + ERROR_MR_MID_NOT_FOUND, /* c000014e (STATUS_NO_EVENT_PAIR) */ + ERROR_UNRECOGNIZED_VOLUME, /* c000014f (STATUS_UNRECOGNIZED_VOLUME) */ + ERROR_SERIAL_NO_DEVICE, /* c0000150 (STATUS_SERIAL_NO_DEVICE_INITED) */ + ERROR_NO_SUCH_ALIAS, /* c0000151 (STATUS_NO_SUCH_ALIAS) */ + ERROR_MEMBER_NOT_IN_ALIAS, /* c0000152 (STATUS_MEMBER_NOT_IN_ALIAS) */ + ERROR_MEMBER_IN_ALIAS, /* c0000153 (STATUS_MEMBER_IN_ALIAS) */ + ERROR_ALIAS_EXISTS, /* c0000154 (STATUS_ALIAS_EXISTS) */ + ERROR_LOGON_NOT_GRANTED, /* c0000155 (STATUS_LOGON_NOT_GRANTED) */ + ERROR_TOO_MANY_SECRETS, /* c0000156 (STATUS_TOO_MANY_SECRETS) */ + ERROR_SECRET_TOO_LONG, /* c0000157 (STATUS_SECRET_TOO_LONG) */ + ERROR_INTERNAL_DB_ERROR, /* c0000158 (STATUS_INTERNAL_DB_ERROR) */ + ERROR_FULLSCREEN_MODE, /* c0000159 (STATUS_FULLSCREEN_MODE) */ + ERROR_TOO_MANY_CONTEXT_IDS, /* c000015a (STATUS_TOO_MANY_CONTEXT_IDS) */ + ERROR_LOGON_TYPE_NOT_GRANTED, /* c000015b (STATUS_LOGON_TYPE_NOT_GRANTED) */ + ERROR_NOT_REGISTRY_FILE, /* c000015c (STATUS_NOT_REGISTRY_FILE) */ + ERROR_NT_CROSS_ENCRYPTION_REQUIRED, /* c000015d (STATUS_NT_CROSS_ENCRYPTION_REQUIRED) */ + ERROR_MR_MID_NOT_FOUND, /* c000015e (STATUS_DOMAIN_CTRLR_CONFIG_ERROR) */ + ERROR_IO_DEVICE, /* c000015f (STATUS_FT_MISSING_MEMBER) */ + ERROR_MR_MID_NOT_FOUND, /* c0000160 (STATUS_ILL_FORMED_SERVICE_ENTRY) */ + ERROR_MR_MID_NOT_FOUND, /* c0000161 (STATUS_ILLEGAL_CHARACTER) */ + ERROR_NO_UNICODE_TRANSLATION, /* c0000162 (STATUS_UNMAPPABLE_CHARACTER) */ + ERROR_MR_MID_NOT_FOUND, /* c0000163 (STATUS_UNDEFINED_CHARACTER) */ + ERROR_MR_MID_NOT_FOUND, /* c0000164 (STATUS_FLOPPY_VOLUME) */ + ERROR_FLOPPY_ID_MARK_NOT_FOUND, /* c0000165 (STATUS_FLOPPY_ID_MARK_NOT_FOUND) */ + ERROR_FLOPPY_WRONG_CYLINDER, /* c0000166 (STATUS_FLOPPY_WRONG_CYLINDER) */ + ERROR_FLOPPY_UNKNOWN_ERROR, /* c0000167 (STATUS_FLOPPY_UNKNOWN_ERROR) */ + ERROR_FLOPPY_BAD_REGISTERS, /* c0000168 (STATUS_FLOPPY_BAD_REGISTERS) */ + ERROR_DISK_RECALIBRATE_FAILED, /* c0000169 (STATUS_DISK_RECALIBRATE_FAILED) */ + ERROR_DISK_OPERATION_FAILED, /* c000016a (STATUS_DISK_OPERATION_FAILED) */ + ERROR_DISK_RESET_FAILED, /* c000016b (STATUS_DISK_RESET_FAILED) */ + ERROR_IRQ_BUSY, /* c000016c (STATUS_SHARED_IRQ_BUSY) */ + ERROR_IO_DEVICE, /* c000016d (STATUS_FT_ORPHANING) */ + ERROR_MR_MID_NOT_FOUND, /* c000016e (STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT) */ + ERROR_MR_MID_NOT_FOUND, /* c000016f */ + ERROR_MR_MID_NOT_FOUND, /* c0000170 */ + ERROR_MR_MID_NOT_FOUND, /* c0000171 */ + ERROR_PARTITION_FAILURE, /* c0000172 (STATUS_PARTITION_FAILURE) */ + ERROR_INVALID_BLOCK_LENGTH, /* c0000173 (STATUS_INVALID_BLOCK_LENGTH) */ + ERROR_DEVICE_NOT_PARTITIONED, /* c0000174 (STATUS_DEVICE_NOT_PARTITIONED) */ + ERROR_UNABLE_TO_LOCK_MEDIA, /* c0000175 (STATUS_UNABLE_TO_LOCK_MEDIA) */ + ERROR_UNABLE_TO_UNLOAD_MEDIA, /* c0000176 (STATUS_UNABLE_TO_UNLOAD_MEDIA) */ + ERROR_EOM_OVERFLOW, /* c0000177 (STATUS_EOM_OVERFLOW) */ + ERROR_NO_MEDIA_IN_DRIVE, /* c0000178 (STATUS_NO_MEDIA) */ + ERROR_MR_MID_NOT_FOUND, /* c0000179 */ + ERROR_NO_SUCH_MEMBER, /* c000017a (STATUS_NO_SUCH_MEMBER) */ + ERROR_INVALID_MEMBER, /* c000017b (STATUS_INVALID_MEMBER) */ + ERROR_KEY_DELETED, /* c000017c (STATUS_KEY_DELETED) */ + ERROR_NO_LOG_SPACE, /* c000017d (STATUS_NO_LOG_SPACE) */ + ERROR_TOO_MANY_SIDS, /* c000017e (STATUS_TOO_MANY_SIDS) */ + ERROR_LM_CROSS_ENCRYPTION_REQUIRED, /* c000017f (STATUS_LM_CROSS_ENCRYPTION_REQUIRED) */ + ERROR_KEY_HAS_CHILDREN, /* c0000180 (STATUS_KEY_HAS_CHILDREN) */ + ERROR_CHILD_MUST_BE_VOLATILE, /* c0000181 (STATUS_CHILD_MUST_BE_VOLATILE) */ + ERROR_INVALID_PARAMETER, /* c0000182 (STATUS_DEVICE_CONFIGURATION_ERROR) */ + ERROR_IO_DEVICE, /* c0000183 (STATUS_DRIVER_INTERNAL_ERROR) */ + ERROR_BAD_COMMAND, /* c0000184 (STATUS_INVALID_DEVICE_STATE) */ + ERROR_IO_DEVICE, /* c0000185 (STATUS_IO_DEVICE_ERROR) */ + ERROR_IO_DEVICE, /* c0000186 (STATUS_DEVICE_PROTOCOL_ERROR) */ + ERROR_MR_MID_NOT_FOUND, /* c0000187 (STATUS_BACKUP_CONTROLLER) */ + ERROR_LOG_FILE_FULL, /* c0000188 (STATUS_LOG_FILE_FULL) */ + ERROR_WRITE_PROTECT, /* c0000189 (STATUS_TOO_LATE) */ + ERROR_NO_TRUST_LSA_SECRET, /* c000018a (STATUS_NO_TRUST_LSA_SECRET) */ + ERROR_NO_TRUST_SAM_ACCOUNT, /* c000018b (STATUS_NO_TRUST_SAM_ACCOUNT) */ + ERROR_TRUSTED_DOMAIN_FAILURE, /* c000018c (STATUS_TRUSTED_DOMAIN_FAILURE) */ + ERROR_TRUSTED_RELATIONSHIP_FAILURE, /* c000018d (STATUS_TRUSTED_RELATIONSHIP_FAILURE) */ + ERROR_EVENTLOG_FILE_CORRUPT, /* c000018e (STATUS_EVENTLOG_FILE_CORRUPT) */ + ERROR_EVENTLOG_CANT_START, /* c000018f (STATUS_EVENTLOG_CANT_START) */ + ERROR_TRUST_FAILURE, /* c0000190 (STATUS_TRUST_FAILURE) */ + ERROR_MR_MID_NOT_FOUND, /* c0000191 (STATUS_MUTANT_LIMIT_EXCEEDED) */ + ERROR_NETLOGON_NOT_STARTED, /* c0000192 (STATUS_NETLOGON_NOT_STARTED) */ + ERROR_ACCOUNT_EXPIRED, /* c0000193 (STATUS_ACCOUNT_EXPIRED) */ + ERROR_POSSIBLE_DEADLOCK, /* c0000194 (STATUS_POSSIBLE_DEADLOCK) */ + ERROR_SESSION_CREDENTIAL_CONFLICT, /* c0000195 (STATUS_NETWORK_CREDENTIAL_CONFLICT) */ + ERROR_REMOTE_SESSION_LIMIT_EXCEEDED, /* c0000196 (STATUS_REMOTE_SESSION_LIMIT) */ + ERROR_EVENTLOG_FILE_CHANGED, /* c0000197 (STATUS_EVENTLOG_FILE_CHANGED) */ + ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT,/* c0000198 (STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT) */ + ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT,/* c0000199 (STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT) */ + ERROR_NOLOGON_SERVER_TRUST_ACCOUNT, /* c000019a (STATUS_NOLOGON_SERVER_TRUST_ACCOUNT) */ + ERROR_DOMAIN_TRUST_INCONSISTENT /* c000019b (STATUS_DOMAIN_TRUST_INCONSISTENT) */ + }; + +static const WORD table_c0000202[109] = + { + ERROR_NO_USER_SESSION_KEY, /* c0000202 (STATUS_NO_USER_SESSION_KEY) */ + ERROR_UNEXP_NET_ERR, /* c0000203 (STATUS_USER_SESSION_DELETED) */ + ERROR_RESOURCE_LANG_NOT_FOUND, /* c0000204 (STATUS_RESOURCE_LANG_NOT_FOUND) */ + ERROR_NOT_ENOUGH_SERVER_MEMORY, /* c0000205 (STATUS_INSUFF_SERVER_RESOURCES) */ + ERROR_INVALID_USER_BUFFER, /* c0000206 (STATUS_INVALID_BUFFER_SIZE) */ + ERROR_INVALID_NETNAME, /* c0000207 (STATUS_INVALID_ADDRESS_COMPONENT) */ + ERROR_INVALID_NETNAME, /* c0000208 (STATUS_INVALID_ADDRESS_WILDCARD) */ + ERROR_TOO_MANY_NAMES, /* c0000209 (STATUS_TOO_MANY_ADDRESSES) */ + ERROR_DUP_NAME, /* c000020a (STATUS_ADDRESS_ALREADY_EXISTS) */ + ERROR_NETNAME_DELETED, /* c000020b (STATUS_ADDRESS_CLOSED) */ + ERROR_NETNAME_DELETED, /* c000020c (STATUS_CONNECTION_DISCONNECTED) */ + ERROR_NETNAME_DELETED, /* c000020d (STATUS_CONNECTION_RESET) */ + ERROR_TOO_MANY_NAMES, /* c000020e (STATUS_TOO_MANY_NODES) */ + ERROR_UNEXP_NET_ERR, /* c000020f (STATUS_TRANSACTION_ABORTED) */ + ERROR_UNEXP_NET_ERR, /* c0000210 (STATUS_TRANSACTION_TIMED_OUT) */ + ERROR_UNEXP_NET_ERR, /* c0000211 (STATUS_TRANSACTION_NO_RELEASE) */ + ERROR_UNEXP_NET_ERR, /* c0000212 (STATUS_TRANSACTION_NO_MATCH) */ + ERROR_UNEXP_NET_ERR, /* c0000213 (STATUS_TRANSACTION_RESPONDED) */ + ERROR_UNEXP_NET_ERR, /* c0000214 (STATUS_TRANSACTION_INVALID_ID) */ + ERROR_UNEXP_NET_ERR, /* c0000215 (STATUS_TRANSACTION_INVALID_TYPE) */ + ERROR_NOT_SUPPORTED, /* c0000216 (STATUS_NOT_SERVER_SESSION) */ + ERROR_NOT_SUPPORTED, /* c0000217 (STATUS_NOT_CLIENT_SESSION) */ + ERROR_MR_MID_NOT_FOUND, /* c0000218 (STATUS_CANNOT_LOAD_REGISTRY_FILE) */ + ERROR_MR_MID_NOT_FOUND, /* c0000219 */ + ERROR_MR_MID_NOT_FOUND, /* c000021a */ + ERROR_MR_MID_NOT_FOUND, /* c000021b */ + ERROR_NO_BROWSER_SERVERS_FOUND, /* c000021c (STATUS_NO_BROWSER_SERVERS_FOUND) */ + ERROR_MR_MID_NOT_FOUND, /* c000021d */ + ERROR_MR_MID_NOT_FOUND, /* c000021e */ + ERROR_MR_MID_NOT_FOUND, /* c000021f */ + ERROR_MAPPED_ALIGNMENT, /* c0000220 (STATUS_MAPPED_ALIGNMENT) */ + ERROR_BAD_EXE_FORMAT, /* c0000221 (STATUS_IMAGE_CHECKSUM_MISMATCH) */ + ERROR_MR_MID_NOT_FOUND, /* c0000222 */ + ERROR_MR_MID_NOT_FOUND, /* c0000223 */ + ERROR_PASSWORD_MUST_CHANGE, /* c0000224 (STATUS_PASSWORD_MUST_CHANGE) */ + ERROR_MR_MID_NOT_FOUND, /* c0000225 */ + ERROR_MR_MID_NOT_FOUND, /* c0000226 */ + ERROR_MR_MID_NOT_FOUND, /* c0000227 */ + ERROR_MR_MID_NOT_FOUND, /* c0000228 */ + ERROR_MR_MID_NOT_FOUND, /* c0000229 */ + 0, /* c000022a */ + 0, /* c000022b */ + ERROR_MR_MID_NOT_FOUND, /* c000022c */ + ERROR_MR_MID_NOT_FOUND, /* c000022d */ + ERROR_MR_MID_NOT_FOUND, /* c000022e */ + ERROR_MR_MID_NOT_FOUND, /* c000022f */ + ERROR_MR_MID_NOT_FOUND, /* c0000230 */ + ERROR_MR_MID_NOT_FOUND, /* c0000231 */ + ERROR_MR_MID_NOT_FOUND, /* c0000232 */ + ERROR_DOMAIN_CONTROLLER_NOT_FOUND, /* c0000233 */ + ERROR_ACCOUNT_LOCKED_OUT, /* c0000234 */ + ERROR_INVALID_HANDLE, /* c0000235 */ + ERROR_CONNECTION_REFUSED, /* c0000236 */ + ERROR_GRACEFUL_DISCONNECT, /* c0000237 */ + ERROR_ADDRESS_ALREADY_ASSOCIATED, /* c0000238 */ + ERROR_ADDRESS_NOT_ASSOCIATED, /* c0000239 */ + ERROR_CONNECTION_INVALID, /* c000023a */ + ERROR_CONNECTION_ACTIVE, /* c000023b */ + ERROR_NETWORK_UNREACHABLE, /* c000023c */ + ERROR_HOST_UNREACHABLE, /* c000023d */ + ERROR_PROTOCOL_UNREACHABLE, /* c000023e */ + ERROR_PORT_UNREACHABLE, /* c000023f */ + ERROR_REQUEST_ABORTED, /* c0000240 */ + ERROR_CONNECTION_ABORTED, /* c0000241 */ + ERROR_MR_MID_NOT_FOUND, /* c0000242 */ + ERROR_USER_MAPPED_FILE, /* c0000243 */ + ERROR_MR_MID_NOT_FOUND, /* c0000244 */ + ERROR_MR_MID_NOT_FOUND, /* c0000245 */ + ERROR_CONNECTION_COUNT_LIMIT, /* c0000246 */ + ERROR_LOGIN_TIME_RESTRICTION, /* c0000247 */ + ERROR_LOGIN_WKSTA_RESTRICTION, /* c0000248 */ + ERROR_BAD_EXE_FORMAT, /* c0000249 */ + ERROR_MR_MID_NOT_FOUND, /* c000024a */ + ERROR_MR_MID_NOT_FOUND, /* c000024b */ + ERROR_MR_MID_NOT_FOUND, /* c000024c */ + ERROR_MR_MID_NOT_FOUND, /* c000024d */ + ERROR_MR_MID_NOT_FOUND, /* c000024e */ + ERROR_MR_MID_NOT_FOUND, /* c000024f */ + ERROR_MR_MID_NOT_FOUND, /* c0000250 */ + ERROR_MR_MID_NOT_FOUND, /* c0000251 */ + ERROR_MR_MID_NOT_FOUND, /* c0000252 */ + ERROR_INTERNAL_ERROR, /* c0000253 */ + ERROR_MR_MID_NOT_FOUND, /* c0000254 */ + ERROR_MR_MID_NOT_FOUND, /* c0000255 */ + ERROR_MR_MID_NOT_FOUND, /* c0000256 */ + ERROR_HOST_UNREACHABLE, /* c0000257 */ + ERROR_MR_MID_NOT_FOUND, /* c0000258 */ + ERROR_LICENSE_QUOTA_EXCEEDED, /* c0000259 */ + ERROR_MR_MID_NOT_FOUND, /* c000025a */ + ERROR_MR_MID_NOT_FOUND, /* c000025b */ + ERROR_MR_MID_NOT_FOUND, /* c000025c */ + ERROR_MR_MID_NOT_FOUND, /* c000025d */ + ERROR_SERVICE_DISABLED, /* c000025e */ + ERROR_MR_MID_NOT_FOUND, /* c000025f */ + ERROR_MR_MID_NOT_FOUND, /* c0000260 */ + ERROR_MR_MID_NOT_FOUND, /* c0000261 */ + ERROR_INVALID_ORDINAL, /* c0000262 */ + ERROR_PROC_NOT_FOUND, /* c0000263 */ + ERROR_NOT_OWNER, /* c0000264 */ + ERROR_TOO_MANY_LINKS, /* c0000265 */ + ERROR_MR_MID_NOT_FOUND, /* c0000266 */ + ERROR_MR_MID_NOT_FOUND, /* c0000267 */ + ERROR_MR_MID_NOT_FOUND, /* c0000268 */ + ERROR_MR_MID_NOT_FOUND, /* c0000269 */ + ERROR_MR_MID_NOT_FOUND, /* c000026a */ + ERROR_MR_MID_NOT_FOUND, /* c000026b */ + ERROR_MR_MID_NOT_FOUND, /* c000026c */ + ERROR_MR_MID_NOT_FOUND, /* c000026d */ + ERROR_NOT_READY /* c000026e (STATUS_VOLUME_DISMOUNTED) */ + }; + +static const WORD table_c0020001[88] = + { + RPC_S_INVALID_STRING_BINDING, /* c0020001 (RPC_NT_INVALID_STRING_BINDING) */ + RPC_S_WRONG_KIND_OF_BINDING, /* c0020002 (RPC_NT_WRONG_KIND_OF_BINDING) */ + ERROR_INVALID_HANDLE, /* c0020003 (RPC_NT_INVALID_BINDING) */ + RPC_S_PROTSEQ_NOT_SUPPORTED, /* c0020004 (RPC_NT_PROTSEQ_NOT_SUPPORTED) */ + RPC_S_INVALID_RPC_PROTSEQ, /* c0020005 (RPC_NT_INVALID_RPC_PROTSEQ) */ + RPC_S_INVALID_STRING_UUID, /* c0020006 (RPC_NT_INVALID_STRING_UUID) */ + RPC_S_INVALID_ENDPOINT_FORMAT, /* c0020007 (RPC_NT_INVALID_ENDPOINT_FORMAT) */ + RPC_S_INVALID_NET_ADDR, /* c0020008 (RPC_NT_INVALID_NET_ADDR) */ + RPC_S_NO_ENDPOINT_FOUND, /* c0020009 (RPC_NT_NO_ENDPOINT_FOUND) */ + RPC_S_INVALID_TIMEOUT, /* c002000a (RPC_NT_INVALID_TIMEOUT) */ + RPC_S_OBJECT_NOT_FOUND, /* c002000b (RPC_NT_OBJECT_NOT_FOUND) */ + RPC_S_ALREADY_REGISTERED, /* c002000c (RPC_NT_ALREADY_REGISTERED) */ + RPC_S_TYPE_ALREADY_REGISTERED, /* c002000d (RPC_NT_TYPE_ALREADY_REGISTERED) */ + RPC_S_ALREADY_LISTENING, /* c002000e (RPC_NT_ALREADY_LISTENING) */ + RPC_S_NO_PROTSEQS_REGISTERED, /* c002000f (RPC_NT_NO_PROTSEQS_REGISTERED) */ + RPC_S_NOT_LISTENING, /* c0020010 (RPC_NT_NOT_LISTENING) */ + RPC_S_UNKNOWN_MGR_TYPE, /* c0020011 (RPC_NT_UNKNOWN_MGR_TYPE) */ + RPC_S_UNKNOWN_IF, /* c0020012 (RPC_NT_UNKNOWN_IF) */ + RPC_S_NO_BINDINGS, /* c0020013 (RPC_NT_NO_BINDINGS) */ + RPC_S_NO_PROTSEQS, /* c0020014 (RPC_NT_NO_PROTSEQS) */ + RPC_S_CANT_CREATE_ENDPOINT, /* c0020015 (RPC_NT_CANT_CREATE_ENDPOINT) */ + RPC_S_OUT_OF_RESOURCES, /* c0020016 (RPC_NT_OUT_OF_RESOURCES) */ + RPC_S_SERVER_UNAVAILABLE, /* c0020017 (RPC_NT_SERVER_UNAVAILABLE) */ + RPC_S_SERVER_TOO_BUSY, /* c0020018 (RPC_NT_SERVER_TOO_BUSY) */ + RPC_S_INVALID_NETWORK_OPTIONS, /* c0020019 (RPC_NT_INVALID_NETWORK_OPTIONS) */ + RPC_S_NO_CALL_ACTIVE, /* c002001a (RPC_NT_NO_CALL_ACTIVE) */ + RPC_S_CALL_FAILED, /* c002001b (RPC_NT_CALL_FAILED) */ + RPC_S_CALL_FAILED_DNE, /* c002001c (RPC_NT_CALL_FAILED_DNE) */ + RPC_S_PROTOCOL_ERROR, /* c002001d (RPC_NT_PROTOCOL_ERROR) */ + ERROR_MR_MID_NOT_FOUND, /* c002001e */ + RPC_S_UNSUPPORTED_TRANS_SYN, /* c002001f (RPC_NT_UNSUPPORTED_TRANS_SYN) */ + ERROR_MR_MID_NOT_FOUND, /* c0020020 */ + RPC_S_UNSUPPORTED_TYPE, /* c0020021 (RPC_NT_UNSUPPORTED_TYPE) */ + RPC_S_INVALID_TAG, /* c0020022 (RPC_NT_INVALID_TAG) */ + RPC_S_INVALID_BOUND, /* c0020023 (RPC_NT_INVALID_BOUND) */ + RPC_S_NO_ENTRY_NAME, /* c0020024 (RPC_NT_NO_ENTRY_NAME) */ + RPC_S_INVALID_NAME_SYNTAX, /* c0020025 (RPC_NT_INVALID_NAME_SYNTAX) */ + RPC_S_UNSUPPORTED_NAME_SYNTAX, /* c0020026 (RPC_NT_UNSUPPORTED_NAME_SYNTAX) */ + ERROR_MR_MID_NOT_FOUND, /* c0020027 */ + RPC_S_UUID_NO_ADDRESS, /* c0020028 (RPC_NT_UUID_NO_ADDRESS) */ + RPC_S_DUPLICATE_ENDPOINT, /* c0020029 (RPC_NT_DUPLICATE_ENDPOINT) */ + RPC_S_UNKNOWN_AUTHN_TYPE, /* c002002a (RPC_NT_UNKNOWN_AUTHN_TYPE) */ + RPC_S_MAX_CALLS_TOO_SMALL, /* c002002b (RPC_NT_MAX_CALLS_TOO_SMALL) */ + RPC_S_STRING_TOO_LONG, /* c002002c (RPC_NT_STRING_TOO_LONG) */ + RPC_S_PROTSEQ_NOT_FOUND, /* c002002d (RPC_NT_PROTSEQ_NOT_FOUND) */ + RPC_S_PROCNUM_OUT_OF_RANGE, /* c002002e (RPC_NT_PROCNUM_OUT_OF_RANGE) */ + RPC_S_BINDING_HAS_NO_AUTH, /* c002002f (RPC_NT_BINDING_HAS_NO_AUTH) */ + RPC_S_UNKNOWN_AUTHN_SERVICE, /* c0020030 (RPC_NT_UNKNOWN_AUTHN_SERVICE) */ + RPC_S_UNKNOWN_AUTHN_LEVEL, /* c0020031 (RPC_NT_UNKNOWN_AUTHN_LEVEL) */ + RPC_S_INVALID_AUTH_IDENTITY, /* c0020032 (RPC_NT_INVALID_AUTH_IDENTITY) */ + RPC_S_UNKNOWN_AUTHZ_SERVICE, /* c0020033 (RPC_NT_UNKNOWN_AUTHZ_SERVICE) */ + EPT_S_INVALID_ENTRY, /* c0020034 (EPT_NT_INVALID_ENTRY) */ + EPT_S_CANT_PERFORM_OP, /* c0020035 (EPT_NT_CANT_PERFORM_OP) */ + EPT_S_NOT_REGISTERED, /* c0020036 (EPT_NT_NOT_REGISTERED) */ + RPC_S_NOTHING_TO_EXPORT, /* c0020037 (RPC_NT_NOTHING_TO_EXPORT) */ + RPC_S_INCOMPLETE_NAME, /* c0020038 (RPC_NT_INCOMPLETE_NAME) */ + RPC_S_INVALID_VERS_OPTION, /* c0020039 (RPC_NT_INVALID_VERS_OPTION) */ + RPC_S_NO_MORE_MEMBERS, /* c002003a (RPC_NT_NO_MORE_MEMBERS) */ + RPC_S_NOT_ALL_OBJS_UNEXPORTED, /* c002003b (RPC_NT_NOT_ALL_OBJS_UNEXPORTED) */ + RPC_S_INTERFACE_NOT_FOUND, /* c002003c (RPC_NT_INTERFACE_NOT_FOUND) */ + RPC_S_ENTRY_ALREADY_EXISTS, /* c002003d (RPC_NT_ENTRY_ALREADY_EXISTS) */ + RPC_S_ENTRY_NOT_FOUND, /* c002003e (RPC_NT_ENTRY_NOT_FOUND) */ + RPC_S_NAME_SERVICE_UNAVAILABLE, /* c002003f (RPC_NT_NAME_SERVICE_UNAVAILABLE) */ + RPC_S_INVALID_NAF_ID, /* c0020040 (RPC_NT_INVALID_NAF_ID) */ + RPC_S_CANNOT_SUPPORT, /* c0020041 (RPC_NT_CANNOT_SUPPORT) */ + RPC_S_NO_CONTEXT_AVAILABLE, /* c0020042 (RPC_NT_NO_CONTEXT_AVAILABLE) */ + RPC_S_INTERNAL_ERROR, /* c0020043 (RPC_NT_INTERNAL_ERROR) */ + RPC_S_ZERO_DIVIDE, /* c0020044 (RPC_NT_ZERO_DIVIDE) */ + RPC_S_ADDRESS_ERROR, /* c0020045 (RPC_NT_ADDRESS_ERROR) */ + RPC_S_FP_DIV_ZERO, /* c0020046 (RPC_NT_FP_DIV_ZERO) */ + RPC_S_FP_UNDERFLOW, /* c0020047 (RPC_NT_FP_UNDERFLOW) */ + RPC_S_FP_OVERFLOW, /* c0020048 (RPC_NT_FP_OVERFLOW) */ + RPC_S_CALL_IN_PROGRESS, /* c0020049 (RPC_NT_CALL_IN_PROGRESS) */ + RPC_S_NO_MORE_BINDINGS, /* c002004a (RPC_NT_NO_MORE_BINDINGS) */ + RPC_S_GROUP_MEMBER_NOT_FOUND, /* c002004b (RPC_NT_GROUP_MEMBER_NOT_FOUND) */ + EPT_S_CANT_CREATE, /* c002004c (EPT_NT_CANT_CREATE) */ + RPC_S_INVALID_OBJECT, /* c002004d (RPC_NT_INVALID_OBJECT) */ + ERROR_MR_MID_NOT_FOUND, /* c002004e */ + RPC_S_NO_INTERFACES, /* c002004f */ + RPC_S_CALL_CANCELLED, /* c0020050 */ + RPC_S_BINDING_INCOMPLETE, /* c0020051 */ + RPC_S_COMM_FAILURE, /* c0020052 */ + RPC_S_UNSUPPORTED_AUTHN_LEVEL, /* c0020053 */ + RPC_S_NO_PRINC_NAME, /* c0020054 */ + RPC_S_NOT_RPC_ERROR, /* c0020055 */ + ERROR_MR_MID_NOT_FOUND, /* c0020056 */ + RPC_S_SEC_PKG_ERROR, /* c0020057 */ + RPC_S_NOT_CANCELLED /* c0020058 */ + }; + +static const WORD table_c0030001[12] = + { + RPC_X_NO_MORE_ENTRIES, /* c0030001 (RPC_NT_NO_MORE_ENTRIES) */ + RPC_X_SS_CHAR_TRANS_OPEN_FAIL, /* c0030002 (RPC_NT_SS_CHAR_TRANS_OPEN_FAIL) */ + RPC_X_SS_CHAR_TRANS_SHORT_FILE, /* c0030003 (RPC_NT_SS_CHAR_TRANS_SHORT_FILE) */ + ERROR_INVALID_HANDLE, /* c0030004 (RPC_NT_SS_IN_NULL_CONTEXT) */ + ERROR_INVALID_HANDLE, /* c0030005 */ + RPC_X_SS_CONTEXT_DAMAGED, /* c0030006 (RPC_NT_SS_CONTEXT_DAMAGED) */ + RPC_X_SS_HANDLES_MISMATCH, /* c0030007 (RPC_NT_SS_HANDLES_MISMATCH) */ + RPC_X_SS_CANNOT_GET_CALL_HANDLE, /* c0030008 (RPC_NT_SS_CANNOT_GET_CALL_HANDLE) */ + RPC_X_NULL_REF_POINTER, /* c0030009 (RPC_NT_NULL_REF_POINTER) */ + RPC_X_ENUM_VALUE_OUT_OF_RANGE, /* c003000a (RPC_NT_ENUM_VALUE_OUT_OF_RANGE) */ + RPC_X_BYTE_COUNT_TOO_SMALL, /* c003000b (RPC_NT_BYTE_COUNT_TOO_SMALL) */ + RPC_X_BAD_STUB_DATA /* c003000c (RPC_NT_BAD_STUB_DATA) */ + }; + +static const WORD table_c0030059[6] = + { + RPC_X_INVALID_ES_ACTION, /* c0030059 */ + RPC_X_WRONG_ES_VERSION, /* c003005a */ + RPC_X_WRONG_STUB_VERSION, /* c003005b */ + RPC_X_INVALID_PIPE_OBJECT, /* c003005c */ + RPC_X_WRONG_PIPE_ORDER, /* c003005d */ + RPC_X_WRONG_PIPE_VERSION /* c003005e */ + }; + +static const ERROR_TABLE ErrorTable[] = + { + { + 0x00000103, 0x0000010e, table_00000103 + }, + { 0x40000002, 0x4000000e, table_40000002 }, + { 0x40020056, 0x40020057, table_40020056 }, + { 0x400200af, 0x400200b0, table_400200af }, + { 0x80000001, 0x80000027, table_80000001 }, + { 0x80090300, 0x80090317, table_80090300 }, + { 0xc0000001, 0xc000019c, table_c0000001 }, + { 0xc0000202, 0xc000026f, table_c0000202 }, + { 0xc0020001, 0xc0020059, table_c0020001 }, + { 0xc0030001, 0xc003000d, table_c0030001 }, + { 0xc0030059, 0xc003005f, table_c0030059 }, + { 0, 0, 0 } /* last entry */ + }; + + +#if 0 +/* currently not assigned values */ +ERROR_ARENA_TRASHED +STATUS_HANDLE_NOT_WAITABLE ERROR_INVALID_HANDLE; +STATUS_LOCK_NOT_GRANTED ERROR_LOCK_VIOLATION; + +RPC_NT_SS_CONTEXT_MISMATCH ERROR_INVALID_HANDLE +#endif + + +/* FUNCTIONS ***************************************************************/ + +/* + * @implemented + */ +VOID +STDCALL +RtlAssert(PVOID FailedAssertion, + PVOID FileName, + ULONG LineNumber, + PCHAR Message) +{ + if (NULL != Message) + { + DbgPrint("Assertion \'%s\' failed at %s line %d: %s\n", + (PCHAR)FailedAssertion, + (PCHAR)FileName, + LineNumber, + Message); + } + else + { + DbgPrint("Assertion \'%s\' failed at %s line %d\n", + (PCHAR)FailedAssertion, + (PCHAR)FileName, + LineNumber); + } + + DbgBreakPoint(); +} + + +/********************************************************************** + * NAME EXPORTED + * RtlNtStatusToDosErrorNoTeb + * + * DESCRIPTION + * Convert an Executive status ID into a DOS error number + * (winerror.h). + * + * ARGUMENTS + * Status The Executive status ID to convert. + * + * RETURN VALUE + * dos error as in winerror.h + * + * REMARK + * RtlNtStatusToDosErrorNoTeb() does the real work. + * + * @implemented + */ +DWORD STDCALL +RtlNtStatusToDosErrorNoTeb(IN NTSTATUS Status) +{ + PERROR_TABLE Table = (PERROR_TABLE)ErrorTable; + + if (!Status || (Status & 0x20000000)) + return Status; + + /* 0xd... is equivalent to 0xc... */ + if ((Status & 0xf0000000) == 0xd0000000) + Status &= ~0x10000000; + + while (Table->Start) + { + if ((ULONG)Status < Table->Start) + break; + + if ((ULONG)Status < Table->End) + { + DWORD ret = Table->Table[(ULONG)Status - Table->Start]; + if (!ret) + ret = Status; /* 0 means 1:1 mapping */ + else if (ret == ERROR_MR_MID_NOT_FOUND) + { + DPRINT1("RTL: RtlNtStatusToDosErrorNoTeb(0x%lx): no valid W32 error mapping\n", Status); + } + return ret; + } + Table++; + } + + /* now some special cases */ + if (HIWORD(Status) == 0xc001) + return LOWORD(Status); + if (HIWORD(Status) == 0x8007) + return LOWORD(Status); + + DbgPrint("RTL: RtlNtStatusToDosErrorNoTeb(0x%lx): no valid W32 error mapping\n", Status); + + return ERROR_MR_MID_NOT_FOUND; +} + + +/********************************************************************** + * NAME EXPORTED + * RtlNtStatusToDosError + * + * DESCRIPTION + * Convert an Executive status ID into a DOS error number + * (winerror.h). + * + * ARGUMENTS + * Status The Executive status ID to convert. + * + * RETURN VALUE + * dos error as in winerror.h + * + * REMARK + * RtlNtStatusToDosErrorNoTeb() does the real work. + * + * @implemented + */ +DWORD STDCALL +RtlNtStatusToDosError(IN NTSTATUS Status) +{ + PTEB Teb = NtCurrentTeb (); + + if (NULL != Teb) + { + Teb->LastStatusValue = Status; + } + return RtlNtStatusToDosErrorNoTeb(Status); +} + + +/********************************************************************** + * NAME EXPORTED + * RtlNtStatusToPsxErrno + * + * DESCRIPTION + * Convert an Executive status ID into a POSIX error number + * (errno.h). + * + * NOTE + * Not present in the legacy WNT (a ReactOS extension to support + * the POSIX+ subsystem). + * + * ARGUMENTS + * Status The Executive status ID to convert. + * + * RETURN VALUE + * errno as in errno.h + * + * REVISIONS + * 1999-11-30 ea + */ +INT STDCALL +RtlNtStatusToPsxErrno(IN NTSTATUS Status) +{ +#if 0 + switch (Status) + {} +#endif + + return -1; /* generic POSIX error */ +} + +/* EOF */ diff --git a/reactos/lib/rtl/heap.c b/reactos/lib/rtl/heap.c new file mode 100644 index 00000000000..b258d1e54b6 --- /dev/null +++ b/reactos/lib/rtl/heap.c @@ -0,0 +1,1756 @@ +/* + * Win32 heap functions + * + * Copyright 1996 Alexandre Julliard + * Copyright 1998 Ulrich Weigand + */ + + +/* Note: the heap data structures are based on what Pietrek describes in his + * book 'Windows 95 System Programming Secrets'. The layout is not exactly + * the same, but could be easily adapted if it turns out some programs + * require it. + */ + +#include +#include +#include +#include +#include + +#define NDEBUG +#include + +#define DPRINTF DPRINT +#define ERR DPRINT +#define SetLastError(x) +#define WARN DPRINT +#define TRACE DPRINT +#define WARN_ON(x) (1) + +#undef assert +#ifdef NDEBUG +#define TRACE_ON(x) (0) +#define assert(x) +#else +#define TRACE_ON(x) (1) +#define assert(x) +#endif + + +static CRITICAL_SECTION RtlpProcessHeapsListLock; + + +typedef struct tagARENA_INUSE +{ + DWORD size; /* Block size; must be the first field */ + WORD threadId; /* Allocating thread id */ + WORD magic; /* Magic number */ +} +ARENA_INUSE; + +typedef struct tagARENA_FREE +{ + DWORD size; /* Block size; must be the first field */ + WORD threadId; /* Freeing thread id */ + WORD magic; /* Magic number */ + struct tagARENA_FREE *next; /* Next free arena */ + struct tagARENA_FREE *prev; /* Prev free arena */ +} +ARENA_FREE; + +#define ARENA_FLAG_FREE 0x00000001 /* flags OR'ed with arena size */ +#define ARENA_FLAG_PREV_FREE 0x00000002 +#define ARENA_SIZE_MASK 0xfffffffc +#define ARENA_INUSE_MAGIC 0x4842 /* Value for arena 'magic' field */ +#define ARENA_FREE_MAGIC 0x4846 /* Value for arena 'magic' field */ + +#define ARENA_INUSE_FILLER 0x55 +#define ARENA_FREE_FILLER 0xaa + +#define QUIET 1 /* Suppress messages */ +#define NOISY 0 /* Report all errors */ + +#define HEAP_NB_FREE_LISTS 4 /* Number of free lists */ + +/* Max size of the blocks on the free lists */ +static const DWORD HEAP_freeListSizes[HEAP_NB_FREE_LISTS] = + { + 0x20, 0x80, 0x200, 0xffffffff + }; + +typedef struct +{ + DWORD size; + ARENA_FREE arena; +} +FREE_LIST_ENTRY; + +struct tagHEAP; + +typedef struct tagSUBHEAP +{ + DWORD size; /* Size of the whole sub-heap */ + DWORD commitSize; /* Committed size of the sub-heap */ + DWORD headerSize; /* Size of the heap header */ + struct tagSUBHEAP *next; /* Next sub-heap */ + struct tagHEAP *heap; /* Main heap structure */ + DWORD magic; /* Magic number */ +} +SUBHEAP, *PSUBHEAP; + +#define SUBHEAP_MAGIC ((DWORD)('S' | ('U'<<8) | ('B'<<16) | ('H'<<24))) + +typedef struct tagHEAP +{ + SUBHEAP subheap; /* First sub-heap */ + struct tagHEAP *next; /* Next heap for this process */ + FREE_LIST_ENTRY freeList[HEAP_NB_FREE_LISTS]; /* Free lists */ + CRITICAL_SECTION critSection; /* Critical section for serialization */ + DWORD flags; /* Heap flags */ + DWORD magic; /* Magic number */ + BYTE filler[4]; /* Make multiple of 8 bytes */ +} +HEAP, *PHEAP; + +#define HEAP_MAGIC ((DWORD)('H' | ('E'<<8) | ('A'<<16) | ('P'<<24))) + +#define HEAP_DEF_SIZE 0x110000 /* Default heap size = 1Mb + 64Kb */ +#define HEAP_MIN_BLOCK_SIZE (sizeof(ARENA_FREE) + 8) /* Min. heap block size */ +#define COMMIT_MASK 0xffff /* bitmask for commit/decommit granularity */ + + +static BOOL HEAP_IsRealArena( HANDLE heap, DWORD flags, LPCVOID block, BOOL quiet ); + + +/*********************************************************************** + * HEAP_Dump + */ +void +HEAP_Dump(PHEAP heap) +{ + int i; + SUBHEAP *subheap; + char *ptr; + + DPRINTF( "Heap: %08lx\n", (DWORD)heap ); + DPRINTF( "Next: %08lx Sub-heaps: %08lx", + (DWORD)heap->next, (DWORD)&heap->subheap ); + subheap = &heap->subheap; + while (subheap->next) + { + DPRINTF( " -> %08lx", (DWORD)subheap->next ); + subheap = subheap->next; + } + + DPRINTF( "\nFree lists:\n Block Stat Size Id\n" ); + for (i = 0; i < HEAP_NB_FREE_LISTS; i++) + DPRINTF( "%08lx free %08lx %04x prev=%08lx next=%08lx\n", + (DWORD)&heap->freeList[i].arena, heap->freeList[i].arena.size, + heap->freeList[i].arena.threadId, + (DWORD)heap->freeList[i].arena.prev, + (DWORD)heap->freeList[i].arena.next ); + + subheap = &heap->subheap; + while (subheap) + { + DWORD freeSize = 0, usedSize = 0, arenaSize = subheap->headerSize; + DPRINTF( "\n\nSub-heap %08lx: size=%08lx committed=%08lx\n", + (DWORD)subheap, subheap->size, subheap->commitSize ); + + DPRINTF( "\n Block Stat Size Id\n" ); + ptr = (char*)subheap + subheap->headerSize; + while (ptr < (char *)subheap + subheap->size) + { + if (*(DWORD *)ptr & ARENA_FLAG_FREE) + { + ARENA_FREE *pArena = (ARENA_FREE *)ptr; + DPRINTF( "%08lx free %08lx %04x prev=%08lx next=%08lx\n", + (DWORD)pArena, pArena->size & ARENA_SIZE_MASK, + pArena->threadId, (DWORD)pArena->prev, + (DWORD)pArena->next); + ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK); + arenaSize += sizeof(ARENA_FREE); + freeSize += pArena->size & ARENA_SIZE_MASK; + } + else if (*(DWORD *)ptr & ARENA_FLAG_PREV_FREE) + { + ARENA_INUSE *pArena = (ARENA_INUSE *)ptr; + DPRINTF( "%08lx Used %08lx %04x back=%08lx\n", + (DWORD)pArena, pArena->size & ARENA_SIZE_MASK, + pArena->threadId, *((DWORD *)pArena - 1)); + ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK); + arenaSize += sizeof(ARENA_INUSE); + usedSize += pArena->size & ARENA_SIZE_MASK; + } + else + { + ARENA_INUSE *pArena = (ARENA_INUSE *)ptr; + DPRINTF( "%08lx used %08lx %04x\n", + (DWORD)pArena, pArena->size & ARENA_SIZE_MASK, + pArena->threadId); + ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK); + arenaSize += sizeof(ARENA_INUSE); + usedSize += pArena->size & ARENA_SIZE_MASK; + } + } + DPRINTF( "\nTotal: Size=%08lx Committed=%08lx Free=%08lx Used=%08lx Arenas=%08lx (%ld%%)\n\n", + subheap->size, subheap->commitSize, freeSize, usedSize, + arenaSize, (arenaSize * 100) / subheap->size ); + subheap = subheap->next; + } +} + + +/*********************************************************************** + * HEAP_GetPtr + * RETURNS + * Pointer to the heap + * NULL: Failure + */ +static PHEAP +HEAP_GetPtr(HANDLE heap) /* [in] Handle to the heap */ +{ + HEAP *heapPtr = (HEAP *)heap; + if (!heapPtr || (heapPtr->magic != HEAP_MAGIC)) + { + ERR("Invalid heap %08x!\n", heap ); + return NULL; + } + if (TRACE_ON(heap) && !HEAP_IsRealArena( heap, 0, NULL, NOISY )) + { + HEAP_Dump( heapPtr ); + assert( FALSE ); + return NULL; + } + return heapPtr; +} + + +/*********************************************************************** + * HEAP_InsertFreeBlock + * + * Insert a free block into the free list. + */ +static VOID +HEAP_InsertFreeBlock(PHEAP heap, + ARENA_FREE *pArena, + BOOL last) +{ + FREE_LIST_ENTRY *pEntry = heap->freeList; + while (pEntry->size < pArena->size) + pEntry++; + if (last) + { + /* insert at end of free list, i.e. before next free list entry */ + pEntry++; + if (pEntry == &heap->freeList[HEAP_NB_FREE_LISTS]) + { + pEntry = heap->freeList; + } + pArena->prev = pEntry->arena.prev; + pArena->prev->next = pArena; + pArena->next = &pEntry->arena; + pEntry->arena.prev = pArena; + } + else + { + /* insert at head of free list */ + pArena->next = pEntry->arena.next; + pArena->next->prev = pArena; + pArena->prev = &pEntry->arena; + pEntry->arena.next = pArena; + } + pArena->size |= ARENA_FLAG_FREE; +} + + +/*********************************************************************** + * HEAP_FindSubHeap + * Find the sub-heap containing a given address. + * + * RETURNS + * Pointer: Success + * NULL: Failure + */ +static PSUBHEAP +HEAP_FindSubHeap(HEAP *heap, /* [in] Heap pointer */ + LPCVOID ptr) /* [in] Address */ +{ + SUBHEAP *sub = &heap->subheap; + while (sub) + { + if (((char *)ptr >= (char *)sub) && + ((char *)ptr < (char *)sub + sub->size)) + return sub; + sub = sub->next; + } + return NULL; +} + + +/*********************************************************************** + * HEAP_Commit + * + * Make sure the heap storage is committed up to (not including) ptr. + */ +static inline BOOL +HEAP_Commit(SUBHEAP *subheap, + void *ptr, + DWORD flags) +{ + DWORD size = (DWORD)((char *)ptr - (char *)subheap); + NTSTATUS Status; + PVOID address; + ULONG commitsize; + + size = (size + COMMIT_MASK) & ~COMMIT_MASK; + if (size > subheap->size) + size = subheap->size; + if (size <= subheap->commitSize) + return TRUE; + + address = (PVOID)((char *)subheap + subheap->commitSize); + commitsize = size - subheap->commitSize; + + if (!(flags & HEAP_NO_VALLOC)) + { + Status = NtAllocateVirtualMemory(NtCurrentProcess(), + &address, + 0, + &commitsize, + MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + if (!NT_SUCCESS(Status)) + { + WARN("Could not commit %08lx bytes at %08lx for heap %08lx\n", + size - subheap->commitSize, + (DWORD)((char *)subheap + subheap->commitSize), + (DWORD)subheap->heap ); + return FALSE; + } + } + subheap->commitSize += commitsize; + return TRUE; +} + + +/*********************************************************************** + * HEAP_Decommit + * + * If possible, decommit the heap storage from (including) 'ptr'. + */ +static inline BOOL HEAP_Decommit( SUBHEAP *subheap, void *ptr, DWORD flags ) +{ + DWORD size = (DWORD)((char *)ptr - (char *)subheap); + PVOID address; + ULONG decommitsize; + NTSTATUS Status; + /* round to next block and add one full block */ + size = ((size + COMMIT_MASK) & ~COMMIT_MASK) + COMMIT_MASK + 1; + if (size >= subheap->commitSize) + return TRUE; + + address = (PVOID)((char *)subheap + size); + decommitsize = subheap->commitSize - size; + + if (!(flags & HEAP_NO_VALLOC)) + { + Status = ZwFreeVirtualMemory(NtCurrentProcess(), + &address, + &decommitsize, + MEM_DECOMMIT); + if (!NT_SUCCESS(Status)) + ; + { + WARN("Could not decommit %08lx bytes at %08lx for heap %08lx\n", + subheap->commitSize - size, + (DWORD)((char *)subheap + size), + (DWORD)subheap->heap ); + return FALSE; + } + } + subheap->commitSize -= decommitsize; + return TRUE; +} + + +/*********************************************************************** + * HEAP_CreateFreeBlock + * + * Create a free block at a specified address. 'size' is the size of the + * whole block, including the new arena. + */ +static void HEAP_CreateFreeBlock( SUBHEAP *subheap, void *ptr, DWORD size ) +{ + ARENA_FREE *pFree; + BOOL last; + + /* Create a free arena */ + + pFree = (ARENA_FREE *)ptr; + pFree->threadId = (DWORD)NtCurrentTeb()->Cid.UniqueThread; + pFree->magic = ARENA_FREE_MAGIC; + + /* If debugging, erase the freed block content */ + + if (TRACE_ON(heap)) + { + char *pEnd = (char *)ptr + size; + if (pEnd > (char *)subheap + subheap->commitSize) + pEnd = (char *)subheap + subheap->commitSize; + if (pEnd > (char *)(pFree + 1)) + memset( pFree + 1, ARENA_FREE_FILLER, pEnd - (char *)(pFree + 1) ); + } + + /* Check if next block is free also */ + + if (((char *)ptr + size < (char *)subheap + subheap->size) && + (*(DWORD *)((char *)ptr + size) & ARENA_FLAG_FREE)) + { + /* Remove the next arena from the free list */ + ARENA_FREE *pNext = (ARENA_FREE *)((char *)ptr + size); + pNext->next->prev = pNext->prev; + pNext->prev->next = pNext->next; + size += (pNext->size & ARENA_SIZE_MASK) + sizeof(*pNext); + if (TRACE_ON(heap)) + memset( pNext, ARENA_FREE_FILLER, sizeof(ARENA_FREE) ); + } + + /* Set the next block PREV_FREE flag and pointer */ + + last = ((char *)ptr + size >= (char *)subheap + subheap->size); + if (!last) + { + DWORD *pNext = (DWORD *)((char *)ptr + size); + *pNext |= ARENA_FLAG_PREV_FREE; + *(ARENA_FREE **)(pNext - 1) = pFree; + } + + /* Last, insert the new block into the free list */ + + pFree->size = size - sizeof(*pFree); + HEAP_InsertFreeBlock( subheap->heap, pFree, last ); +} + + +/*********************************************************************** + * HEAP_MakeInUseBlockFree + * + * Turn an in-use block into a free block. Can also decommit the end of + * the heap, and possibly even free the sub-heap altogether. + */ +static void HEAP_MakeInUseBlockFree( SUBHEAP *subheap, ARENA_INUSE *pArena, + DWORD flags) +{ + ARENA_FREE *pFree; + DWORD size = (pArena->size & ARENA_SIZE_MASK) + sizeof(*pArena); + + /* Check if we can merge with previous block */ + + if (pArena->size & ARENA_FLAG_PREV_FREE) + { + pFree = *((ARENA_FREE **)pArena - 1); + size += (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE); + /* Remove it from the free list */ + pFree->next->prev = pFree->prev; + pFree->prev->next = pFree->next; + } + else + pFree = (ARENA_FREE *)pArena; + + /* Create a free block */ + + HEAP_CreateFreeBlock( subheap, pFree, size ); + size = (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE); + if ((char *)pFree + size < (char *)subheap + subheap->size) + return; /* Not the last block, so nothing more to do */ + + /* Free the whole sub-heap if it's empty and not the original one */ + + if (((char *)pFree == (char *)subheap + subheap->headerSize) && + (subheap != &subheap->heap->subheap)) + { + SUBHEAP *pPrev = &subheap->heap->subheap; + /* Remove the free block from the list */ + pFree->next->prev = pFree->prev; + pFree->prev->next = pFree->next; + /* Remove the subheap from the list */ + while (pPrev && (pPrev->next != subheap)) + pPrev = pPrev->next; + if (pPrev) + pPrev->next = subheap->next; + /* Free the memory */ + subheap->magic = 0; + if (!(flags & HEAP_NO_VALLOC)) + { + ULONG dummySize = 0; + ZwFreeVirtualMemory(NtCurrentProcess(), + (PVOID*)&subheap, + &dummySize, + MEM_RELEASE); + } + return; + } + + /* Decommit the end of the heap */ +} + + +/*********************************************************************** + * HEAP_ShrinkBlock + * + * Shrink an in-use block. + */ +static void HEAP_ShrinkBlock(SUBHEAP *subheap, ARENA_INUSE *pArena, DWORD size) +{ + if ((pArena->size & ARENA_SIZE_MASK) >= size + HEAP_MIN_BLOCK_SIZE) + { + HEAP_CreateFreeBlock( subheap, (char *)(pArena + 1) + size, + (pArena->size & ARENA_SIZE_MASK) - size ); + /* assign size plus previous arena flags */ + pArena->size = size | (pArena->size & ~ARENA_SIZE_MASK); + } + else + { + /* Turn off PREV_FREE flag in next block */ + char *pNext = (char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK); + if (pNext < (char *)subheap + subheap->size) + *(DWORD *)pNext &= ~ARENA_FLAG_PREV_FREE; + } +} + +/*********************************************************************** + * HEAP_InitSubHeap + */ +static BOOL HEAP_InitSubHeap( HEAP *heap, LPVOID address, DWORD flags, + DWORD commitSize, DWORD totalSize ) +{ + SUBHEAP *subheap = (SUBHEAP *)address; + FREE_LIST_ENTRY *pEntry; + int i; + NTSTATUS Status; + + /* Commit memory */ + if (!(flags & HEAP_NO_VALLOC)) + { + Status = ZwAllocateVirtualMemory(NtCurrentProcess(), + &address, + 0, + (PULONG)&commitSize, + MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + if (!NT_SUCCESS(Status)) + { + WARN("Could not commit %08lx bytes for sub-heap %08lx\n", + commitSize, (DWORD)address ); + return FALSE; + } + } + + /* Fill the sub-heap structure */ + + subheap = (SUBHEAP *)address; + subheap->heap = heap; + subheap->size = totalSize; + subheap->commitSize = commitSize; + subheap->magic = SUBHEAP_MAGIC; + + if ( subheap != (SUBHEAP *)heap ) + { + /* If this is a secondary subheap, insert it into list */ + + subheap->headerSize = sizeof(SUBHEAP); + subheap->next = heap->subheap.next; + heap->subheap.next = subheap; + } + else + { + /* If this is a primary subheap, initialize main heap */ + + subheap->headerSize = sizeof(HEAP); + subheap->next = NULL; + heap->next = NULL; + heap->flags = flags; + heap->magic = HEAP_MAGIC; + + /* Build the free lists */ + + for (i = 0, pEntry = heap->freeList; i < HEAP_NB_FREE_LISTS; i++, pEntry++) + { + pEntry->size = HEAP_freeListSizes[i]; + pEntry->arena.size = 0 | ARENA_FLAG_FREE; + pEntry->arena.next = i < HEAP_NB_FREE_LISTS-1 ? + &heap->freeList[i+1].arena : &heap->freeList[0].arena; + pEntry->arena.prev = i ? &heap->freeList[i-1].arena : + &heap->freeList[HEAP_NB_FREE_LISTS-1].arena; + pEntry->arena.threadId = 0; + pEntry->arena.magic = ARENA_FREE_MAGIC; + } + + /* Initialize critical section */ + + RtlInitializeCriticalSection( &heap->critSection ); + } + + /* Create the first free block */ + + HEAP_CreateFreeBlock( subheap, (LPBYTE)subheap + subheap->headerSize, + subheap->size - subheap->headerSize ); + + return TRUE; +} + +/*********************************************************************** + * HEAP_CreateSubHeap + * + * Create a sub-heap of the given size. + * If heap == NULL, creates a main heap. + */ +static SUBHEAP *HEAP_CreateSubHeap(PVOID BaseAddress, + HEAP *heap, DWORD flags, + DWORD commitSize, DWORD totalSize ) +{ + LPVOID address; + NTSTATUS Status; + + /* Round-up sizes on a 64K boundary */ + + totalSize = (totalSize + 0xffff) & 0xffff0000; + commitSize = (commitSize + 0xffff) & 0xffff0000; + if (!commitSize) + commitSize = 0x10000; + if (totalSize < commitSize) + totalSize = commitSize; + + /* Allocate the memory block */ + address = BaseAddress; + if (!(flags & HEAP_NO_VALLOC)) + { + Status = ZwAllocateVirtualMemory(NtCurrentProcess(), + &address, + 0, + (PULONG)&totalSize, + MEM_RESERVE | MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + if (!NT_SUCCESS(Status)) + { + WARN("Could not VirtualAlloc %08lx bytes\n", + totalSize ); + return NULL; + } + } + + /* Initialize subheap */ + + if (!HEAP_InitSubHeap( heap? heap : (HEAP *)address, + address, flags, commitSize, totalSize )) + { + if (address && !(flags & HEAP_NO_VALLOC)) + { + ULONG dummySize = 0; + ZwFreeVirtualMemory(NtCurrentProcess(), + &address, + &dummySize, + MEM_RELEASE); + } + return NULL; + } + + return (SUBHEAP *)address; +} + + +/*********************************************************************** + * HEAP_FindFreeBlock + * + * Find a free block at least as large as the requested size, and make sure + * the requested size is committed. + */ +static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, DWORD size, + SUBHEAP **ppSubHeap ) +{ + SUBHEAP *subheap; + ARENA_FREE *pArena; + FREE_LIST_ENTRY *pEntry = heap->freeList; + + /* Find a suitable free list, and in it find a block large enough */ + + while (pEntry->size < size) + pEntry++; + pArena = pEntry->arena.next; + while (pArena != &heap->freeList[0].arena) + { + DWORD arena_size = (pArena->size & ARENA_SIZE_MASK) + + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE); + if (arena_size >= size) + { + subheap = HEAP_FindSubHeap( heap, pArena ); + if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE) + + size + HEAP_MIN_BLOCK_SIZE, + heap->flags)) + return NULL; + *ppSubHeap = subheap; + return pArena; + } + + pArena = pArena->next; + } + + /* If no block was found, attempt to grow the heap */ + + if (!(heap->flags & HEAP_GROWABLE)) + { + WARN("Not enough space in heap %08lx for %08lx bytes\n", + (DWORD)heap, size ); + return NULL; + } + /* make sure that we have a big enough size *committed* to fit another + * last free arena in ! + * So just one heap struct, one first free arena which will eventually + * get inuse, and HEAP_MIN_BLOCK_SIZE for the second free arena that + * might get assigned all remaining free space in HEAP_ShrinkBlock() */ + size += sizeof(SUBHEAP) + sizeof(ARENA_FREE) + HEAP_MIN_BLOCK_SIZE; + if (!(subheap = HEAP_CreateSubHeap( NULL, heap, heap->flags, size, + max( HEAP_DEF_SIZE, size ) ))) + return NULL; + + TRACE("created new sub-heap %08lx of %08lx bytes for heap %08lx\n", + (DWORD)subheap, size, (DWORD)heap ); + + *ppSubHeap = subheap; + return (ARENA_FREE *)(subheap + 1); +} + + +/*********************************************************************** + * HEAP_IsValidArenaPtr + * + * Check that the pointer is inside the range possible for arenas. + */ +static BOOL HEAP_IsValidArenaPtr( HEAP *heap, void *ptr ) +{ + int i; + SUBHEAP *subheap = HEAP_FindSubHeap( heap, ptr ); + if (!subheap) + return FALSE; + if ((char *)ptr >= (char *)subheap + subheap->headerSize) + return TRUE; + if (subheap != &heap->subheap) + return FALSE; + for (i = 0; i < HEAP_NB_FREE_LISTS; i++) + if (ptr == (void *)&heap->freeList[i].arena) + return TRUE; + return FALSE; +} + + +/*********************************************************************** + * HEAP_ValidateFreeArena + */ +static BOOL HEAP_ValidateFreeArena( SUBHEAP *subheap, ARENA_FREE *pArena ) +{ + char *heapEnd = (char *)subheap + subheap->size; + + /* Check magic number */ + if (pArena->magic != ARENA_FREE_MAGIC) + { + ERR("Heap %08lx: invalid free arena magic for %08lx\n", + (DWORD)subheap->heap, (DWORD)pArena ); + return FALSE; + } + /* Check size flags */ + if (!(pArena->size & ARENA_FLAG_FREE) || + (pArena->size & ARENA_FLAG_PREV_FREE)) + { + ERR("Heap %08lx: bad flags %lx for free arena %08lx\n", + (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena ); + } + /* Check arena size */ + if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd) + { + ERR("Heap %08lx: bad size %08lx for free arena %08lx\n", + (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena ); + return FALSE; + } + /* Check that next pointer is valid */ + if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->next )) + { + ERR("Heap %08lx: bad next ptr %08lx for arena %08lx\n", + (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena ); + return FALSE; + } + /* Check that next arena is free */ + if (!(pArena->next->size & ARENA_FLAG_FREE) || + (pArena->next->magic != ARENA_FREE_MAGIC)) + { + ERR("Heap %08lx: next arena %08lx invalid for %08lx\n", + (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena ); + return FALSE; + } + /* Check that prev pointer is valid */ + if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->prev )) + { + ERR("Heap %08lx: bad prev ptr %08lx for arena %08lx\n", + (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena ); + return FALSE; + } + /* Check that prev arena is free */ + if (!(pArena->prev->size & ARENA_FLAG_FREE) || + (pArena->prev->magic != ARENA_FREE_MAGIC)) + { + ERR("Heap %08lx: prev arena %08lx invalid for %08lx\n", + (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena ); + return FALSE; + } + /* Check that next block has PREV_FREE flag */ + if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd) + { + if (!(*(DWORD *)((char *)(pArena + 1) + + (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE)) + { + ERR("Heap %08lx: free arena %08lx next block has no PREV_FREE flag\n", + (DWORD)subheap->heap, (DWORD)pArena ); + return FALSE; + } + /* Check next block back pointer */ + if (*((ARENA_FREE **)((char *)(pArena + 1) + + (pArena->size & ARENA_SIZE_MASK)) - 1) != pArena) + { + ERR("Heap %08lx: arena %08lx has wrong back ptr %08lx\n", + (DWORD)subheap->heap, (DWORD)pArena, + *((DWORD *)((char *)(pArena+1)+ (pArena->size & ARENA_SIZE_MASK)) - 1)); + return FALSE; + } + } + return TRUE; +} + + +/*********************************************************************** + * HEAP_ValidateInUseArena + */ +static BOOL HEAP_ValidateInUseArena( SUBHEAP *subheap, ARENA_INUSE *pArena, BOOL quiet ) +{ + char *heapEnd = (char *)subheap + subheap->size; + + /* Check magic number */ + if (pArena->magic != ARENA_INUSE_MAGIC) + { + if (quiet == NOISY) + { + ERR("Heap %08lx: invalid in-use arena magic for %08lx\n", + (DWORD)subheap->heap, (DWORD)pArena ); + if (TRACE_ON(heap)) + HEAP_Dump( subheap->heap ); + } + else if (WARN_ON(heap)) + { + WARN("Heap %08lx: invalid in-use arena magic for %08lx\n", + (DWORD)subheap->heap, (DWORD)pArena ); + if (TRACE_ON(heap)) + HEAP_Dump( subheap->heap ); + } + return FALSE; + } + /* Check size flags */ + if (pArena->size & ARENA_FLAG_FREE) + { + ERR("Heap %08lx: bad flags %lx for in-use arena %08lx\n", + (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena ); + return FALSE; + } + /* Check arena size */ + if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd) + { + ERR("Heap %08lx: bad size %08lx for in-use arena %08lx\n", + (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena ); + return FALSE; + } + /* Check next arena PREV_FREE flag */ + if (((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd) && + (*(DWORD *)((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE)) + { + ERR("Heap %08lx: in-use arena %08lx next block has PREV_FREE flag\n", + (DWORD)subheap->heap, (DWORD)pArena ); + return FALSE; + } + /* Check prev free arena */ + if (pArena->size & ARENA_FLAG_PREV_FREE) + { + ARENA_FREE *pPrev = *((ARENA_FREE **)pArena - 1); + /* Check prev pointer */ + if (!HEAP_IsValidArenaPtr( subheap->heap, pPrev )) + { + ERR("Heap %08lx: bad back ptr %08lx for arena %08lx\n", + (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena ); + return FALSE; + } + /* Check that prev arena is free */ + if (!(pPrev->size & ARENA_FLAG_FREE) || + (pPrev->magic != ARENA_FREE_MAGIC)) + { + ERR("Heap %08lx: prev arena %08lx invalid for in-use %08lx\n", + (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena ); + return FALSE; + } + /* Check that prev arena is really the previous block */ + if ((char *)(pPrev + 1) + (pPrev->size & ARENA_SIZE_MASK) != (char *)pArena) + { + ERR("Heap %08lx: prev arena %08lx is not prev for in-use %08lx\n", + (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena ); + return FALSE; + } + } + return TRUE; +} + + +/*********************************************************************** + * HEAP_IsInsideHeap + * Checks whether the pointer points to a block inside a given heap. + * + * NOTES + * Should this return BOOL32? + * + * RETURNS + * !0: Success + * 0: Failure + */ +int HEAP_IsInsideHeap( + HANDLE heap, /* [in] Heap */ + DWORD flags, /* [in] Flags */ + LPCVOID ptr /* [in] Pointer */ +) +{ + HEAP *heapPtr = HEAP_GetPtr( heap ); + SUBHEAP *subheap; + int ret; + + /* Validate the parameters */ + + if (!heapPtr) + return 0; + flags |= heapPtr->flags; + if (!(flags & HEAP_NO_SERIALIZE)) + RtlEnterCriticalSection( &heapPtr->critSection ); + ret = (((subheap = HEAP_FindSubHeap( heapPtr, ptr )) != NULL) && + (((char *)ptr >= (char *)subheap + subheap->headerSize + + sizeof(ARENA_INUSE)))); + if (!(flags & HEAP_NO_SERIALIZE)) + RtlLeaveCriticalSection( &heapPtr->critSection ); + return ret; +} + + + + +/*********************************************************************** + * HEAP_IsRealArena [Internal] + * Validates a block is a valid arena. + * + * RETURNS + * TRUE: Success + * FALSE: Failure + */ +static BOOL HEAP_IsRealArena( + HANDLE heap, /* [in] Handle to the heap */ + DWORD flags, /* [in] Bit flags that control access during operation */ + LPCVOID block, /* [in] Optional pointer to memory block to validate */ + BOOL quiet /* [in] Flag - if true, HEAP_ValidateInUseArena + * does not complain */ +) +{ + SUBHEAP *subheap; + HEAP *heapPtr = (HEAP *)(heap); + BOOL ret = TRUE; + + if (!heapPtr || (heapPtr->magic != HEAP_MAGIC)) + { + ERR("Invalid heap %08x!\n", heap ); + return FALSE; + } + + flags &= HEAP_NO_SERIALIZE; + flags |= heapPtr->flags; + /* calling HeapLock may result in infinite recursion, so do the critsect directly */ + if (!(flags & HEAP_NO_SERIALIZE)) + RtlEnterCriticalSection( &heapPtr->critSection ); + + if (block) + { + /* Only check this single memory block */ + + /* The following code is really HEAP_IsInsideHeap * + * with serialization already done. */ + if (!(subheap = HEAP_FindSubHeap( heapPtr, block )) || + ((char *)block < (char *)subheap + subheap->headerSize + + sizeof(ARENA_INUSE))) + { + if (quiet == NOISY) + { + ERR("Heap %08lx: block %08lx is not inside heap\n", + (DWORD)heap, (DWORD)block ); + } + else if (WARN_ON(heap)) + { + WARN("Heap %08lx: block %08lx is not inside heap\n", + (DWORD)heap, (DWORD)block ); + } + ret = FALSE; + } + else + ret = HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)block - 1, quiet ); + + if (!(flags & HEAP_NO_SERIALIZE)) + RtlLeaveCriticalSection( &heapPtr->critSection ); + return ret; + } + + subheap = &heapPtr->subheap; + while (subheap && ret) + { + char *ptr = (char *)subheap + subheap->headerSize; + while (ptr < (char *)subheap + subheap->size) + { + if (*(DWORD *)ptr & ARENA_FLAG_FREE) + { + if (!HEAP_ValidateFreeArena( subheap, (ARENA_FREE *)ptr )) + { + ret = FALSE; + break; + } + ptr += sizeof(ARENA_FREE) + (*(DWORD *)ptr & ARENA_SIZE_MASK); + } + else + { + if (!HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)ptr, NOISY )) + { + ret = FALSE; + break; + } + ptr += sizeof(ARENA_INUSE) + (*(DWORD *)ptr & ARENA_SIZE_MASK); + } + } + subheap = subheap->next; + } + + if (!(flags & HEAP_NO_SERIALIZE)) + RtlLeaveCriticalSection( &heapPtr->critSection ); + return ret; +} + + +/*********************************************************************** + * HeapCreate (KERNEL32.336) + * RETURNS + * Handle of heap: Success + * NULL: Failure + * + * @implemented + */ +HANDLE STDCALL +RtlCreateHeap(ULONG flags, + PVOID BaseAddress, + ULONG maxSize, + ULONG initialSize, + PVOID Unknown, + PRTL_HEAP_DEFINITION Definition) +{ + SUBHEAP *subheap; + ULONG i; + + /* Allocate the heap block */ + + if (!maxSize) + { + maxSize = HEAP_DEF_SIZE; + flags |= HEAP_GROWABLE; + } + if (!(subheap = HEAP_CreateSubHeap( BaseAddress, NULL, flags, initialSize, maxSize ))) + { + return 0; + } + + RtlEnterCriticalSection (&RtlpProcessHeapsListLock); + for (i = 0; i < NtCurrentPeb ()->NumberOfHeaps; i++) + { + if (NtCurrentPeb ()->ProcessHeaps[i] == NULL) + { + NtCurrentPeb()->ProcessHeaps[i] = (PVOID)subheap; + break; + } + } + RtlLeaveCriticalSection (&RtlpProcessHeapsListLock); + + return (HANDLE)subheap; +} + +/*********************************************************************** + * HeapDestroy (KERNEL32.337) + * RETURNS + * TRUE: Success + * FALSE: Failure + * + * @implemented + */ +BOOL STDCALL +RtlDestroyHeap(HANDLE heap) /* [in] Handle of heap */ +{ + HEAP *heapPtr = HEAP_GetPtr( heap ); + SUBHEAP *subheap; + ULONG i, flags; + + TRACE("%08x\n", heap ); + if (!heapPtr) + return FALSE; + + RtlEnterCriticalSection (&RtlpProcessHeapsListLock); + for (i = 0; i < NtCurrentPeb ()->NumberOfHeaps; i++) + { + if (NtCurrentPeb ()->ProcessHeaps[i] == heap) + { + NtCurrentPeb()->ProcessHeaps[i] = NULL; + break; + } + } + RtlLeaveCriticalSection (&RtlpProcessHeapsListLock); + + RtlDeleteCriticalSection( &heapPtr->critSection ); + subheap = &heapPtr->subheap; + // We must save the flags. The first subheap is located after + // the heap structure. If we release the first subheap, + // we release also the heap structure. + flags = heapPtr->flags; + while (subheap) + { + SUBHEAP *next = subheap->next; + + if (!(flags & HEAP_NO_VALLOC)) + { + ULONG dummySize = 0; + ZwFreeVirtualMemory(NtCurrentProcess(), + (PVOID*)&subheap, + &dummySize, + MEM_RELEASE); + } + subheap = next; + } + return TRUE; +} + + +/*********************************************************************** + * HeapAlloc (KERNEL32.334) + * RETURNS + * Pointer to allocated memory block + * NULL: Failure + * 0x7d030f60--invalid flags in RtlHeapAllocate + * @implemented + */ +PVOID STDCALL +RtlAllocateHeap(HANDLE heap, /* [in] Handle of private heap block */ + ULONG flags, /* [in] Heap allocation control flags */ + ULONG size) /* [in] Number of bytes to allocate */ +{ + ARENA_FREE *pArena; + ARENA_INUSE *pInUse; + SUBHEAP *subheap; + HEAP *heapPtr = HEAP_GetPtr( heap ); + + /* Validate the parameters */ + + if (!heapPtr) + { + if (flags & HEAP_GENERATE_EXCEPTIONS) + RtlRaiseStatus( STATUS_NO_MEMORY ); + return NULL; + } + flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY; + flags |= heapPtr->flags; + if (!(flags & HEAP_NO_SERIALIZE)) + RtlEnterCriticalSection( &heapPtr->critSection ); + size = (size + 7) & ~7; + if (size < HEAP_MIN_BLOCK_SIZE) + size = HEAP_MIN_BLOCK_SIZE; + + /* Locate a suitable free block */ + + if (!(pArena = HEAP_FindFreeBlock( heapPtr, size, &subheap ))) + { + TRACE("(%08x,%08lx,%08lx): returning NULL\n", + heap, flags, size ); + if (!(flags & HEAP_NO_SERIALIZE)) + RtlLeaveCriticalSection( &heapPtr->critSection ); + if (flags & HEAP_GENERATE_EXCEPTIONS) + RtlRaiseStatus( STATUS_NO_MEMORY ); + return NULL; + } + + /* Remove the arena from the free list */ + + pArena->next->prev = pArena->prev; + pArena->prev->next = pArena->next; + + /* Build the in-use arena */ + + pInUse = (ARENA_INUSE *)pArena; + pInUse->size = (pInUse->size & ~ARENA_FLAG_FREE) + + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE); + pInUse->threadId = (DWORD)NtCurrentTeb()->Cid.UniqueThread; + pInUse->magic = ARENA_INUSE_MAGIC; + + /* Shrink the block */ + + HEAP_ShrinkBlock( subheap, pInUse, size ); + + if (flags & HEAP_ZERO_MEMORY) + memset( pInUse + 1, 0, pInUse->size & ARENA_SIZE_MASK ); + else if (TRACE_ON(heap)) + memset( pInUse + 1, ARENA_INUSE_FILLER, pInUse->size & ARENA_SIZE_MASK ); + + if (!(flags & HEAP_NO_SERIALIZE)) + RtlLeaveCriticalSection( &heapPtr->critSection ); + + TRACE("(%08x,%08lx,%08lx): returning %08lx\n", + heap, flags, size, (DWORD)(pInUse + 1) ); + return (LPVOID)(pInUse + 1); +} + + +/*********************************************************************** + * HeapFree (KERNEL32.338) + * RETURNS + * TRUE: Success + * FALSE: Failure + * + * @implemented + */ +BOOLEAN STDCALL RtlFreeHeap( + HANDLE heap, /* [in] Handle of heap */ + ULONG flags, /* [in] Heap freeing flags */ + PVOID ptr /* [in] Address of memory to free */ +) +{ + ARENA_INUSE *pInUse; + SUBHEAP *subheap; + HEAP *heapPtr = HEAP_GetPtr( heap ); + + /* Validate the parameters */ + + if (!heapPtr) + return FALSE; + if (!ptr) /* Freeing a NULL ptr is doesn't indicate an error in Win2k */ + { + WARN("(%08x,%08lx,%08lx): asked to free NULL\n", + heap, flags, (DWORD)ptr ); + return TRUE; + } + + flags &= HEAP_NO_SERIALIZE; + flags |= heapPtr->flags; + if (!(flags & HEAP_NO_SERIALIZE)) + RtlEnterCriticalSection( &heapPtr->critSection ); + if (!HEAP_IsRealArena( heap, HEAP_NO_SERIALIZE, ptr, QUIET )) + { + if (!(flags & HEAP_NO_SERIALIZE)) + RtlLeaveCriticalSection( &heapPtr->critSection ); + TRACE("(%08x,%08lx,%08lx): returning FALSE\n", + heap, flags, (DWORD)ptr ); + return FALSE; + } + + /* Turn the block into a free block */ + + pInUse = (ARENA_INUSE *)ptr - 1; + subheap = HEAP_FindSubHeap( heapPtr, pInUse ); + HEAP_MakeInUseBlockFree( subheap, pInUse, heapPtr->flags ); + + if (!(flags & HEAP_NO_SERIALIZE)) + RtlLeaveCriticalSection( &heapPtr->critSection ); + + TRACE("(%08x,%08lx,%08lx): returning TRUE\n", + heap, flags, (DWORD)ptr ); + return TRUE; +} + + +/*********************************************************************** + * HeapReAlloc (KERNEL32.340) + * RETURNS + * Pointer to reallocated memory block + * NULL: Failure + * 0x7d030f60--invalid flags in RtlHeapAllocate + * @implemented + */ +LPVOID STDCALL RtlReAllocateHeap( + HANDLE heap, /* [in] Handle of heap block */ + DWORD flags, /* [in] Heap reallocation flags */ + LPVOID ptr, /* [in] Address of memory to reallocate */ + DWORD size /* [in] Number of bytes to reallocate */ +) +{ + ARENA_INUSE *pArena; + DWORD oldSize; + HEAP *heapPtr; + SUBHEAP *subheap; + + if (!ptr) + return RtlAllocateHeap( heap, flags, size ); /* FIXME: correct? */ + if (!(heapPtr = HEAP_GetPtr( heap ))) + return FALSE; + + /* Validate the parameters */ + + flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY | + HEAP_REALLOC_IN_PLACE_ONLY; + flags |= heapPtr->flags; + size = (size + 7) & ~7; + if (size < HEAP_MIN_BLOCK_SIZE) + size = HEAP_MIN_BLOCK_SIZE; + + if (!(flags & HEAP_NO_SERIALIZE)) + RtlEnterCriticalSection( &heapPtr->critSection ); + if (!HEAP_IsRealArena( heap, HEAP_NO_SERIALIZE, ptr, QUIET )) + { + if (!(flags & HEAP_NO_SERIALIZE)) + RtlLeaveCriticalSection( &heapPtr->critSection ); + TRACE("(%08x,%08lx,%08lx,%08lx): returning NULL\n", + heap, flags, (DWORD)ptr, size ); + if (flags & HEAP_GENERATE_EXCEPTIONS) + RtlRaiseStatus( STATUS_NO_MEMORY ); + return NULL; + } + + /* Check if we need to grow the block */ + + pArena = (ARENA_INUSE *)ptr - 1; + pArena->threadId = (DWORD)NtCurrentTeb()->Cid.UniqueThread; + + subheap = HEAP_FindSubHeap( heapPtr, pArena ); + oldSize = (pArena->size & ARENA_SIZE_MASK); + if (size > oldSize) + { + char *pNext = (char *)(pArena + 1) + oldSize; + if ((pNext < (char *)subheap + subheap->size) && + (*(DWORD *)pNext & ARENA_FLAG_FREE) && + (oldSize + (*(DWORD *)pNext & ARENA_SIZE_MASK) + sizeof(ARENA_FREE) >= size)) + { + /* The next block is free and large enough */ + ARENA_FREE *pFree = (ARENA_FREE *)pNext; + pFree->next->prev = pFree->prev; + pFree->prev->next = pFree->next; + pArena->size += (pFree->size & ARENA_SIZE_MASK) + sizeof(*pFree); + if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE) + + size + HEAP_MIN_BLOCK_SIZE, + heapPtr->flags)) + { + if (!(flags & HEAP_NO_SERIALIZE)) + RtlLeaveCriticalSection( &heapPtr->critSection ); + if (flags & HEAP_GENERATE_EXCEPTIONS) + RtlRaiseStatus( STATUS_NO_MEMORY ); + return NULL; + } + HEAP_ShrinkBlock( subheap, pArena, size ); + } + else /* Do it the hard way */ + { + ARENA_FREE *pNew; + ARENA_INUSE *pInUse; + SUBHEAP *newsubheap; + + if ((flags & HEAP_REALLOC_IN_PLACE_ONLY) || + !(pNew = HEAP_FindFreeBlock( heapPtr, size, &newsubheap ))) + { + if (!(flags & HEAP_NO_SERIALIZE)) + RtlLeaveCriticalSection( &heapPtr->critSection ); + if (flags & HEAP_GENERATE_EXCEPTIONS) + RtlRaiseStatus( STATUS_NO_MEMORY ); + return NULL; + } + + /* Build the in-use arena */ + + pNew->next->prev = pNew->prev; + pNew->prev->next = pNew->next; + pInUse = (ARENA_INUSE *)pNew; + pInUse->size = (pInUse->size & ~ARENA_FLAG_FREE) + + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE); + pInUse->threadId = (DWORD)NtCurrentTeb()->Cid.UniqueThread; + pInUse->magic = ARENA_INUSE_MAGIC; + HEAP_ShrinkBlock( newsubheap, pInUse, size ); + memcpy( pInUse + 1, pArena + 1, oldSize ); + + /* Free the previous block */ + + HEAP_MakeInUseBlockFree( subheap, pArena, flags ); + subheap = newsubheap; + pArena = pInUse; + } + } + else + HEAP_ShrinkBlock( subheap, pArena, size ); /* Shrink the block */ + + /* Clear the extra bytes if needed */ + + if (size > oldSize) + { + if (flags & HEAP_ZERO_MEMORY) + memset( (char *)(pArena + 1) + oldSize, 0, + (pArena->size & ARENA_SIZE_MASK) - oldSize ); + else if (TRACE_ON(heap)) + memset( (char *)(pArena + 1) + oldSize, ARENA_INUSE_FILLER, + (pArena->size & ARENA_SIZE_MASK) - oldSize ); + } + + /* Return the new arena */ + + if (!(flags & HEAP_NO_SERIALIZE)) + RtlLeaveCriticalSection( &heapPtr->critSection ); + + TRACE("(%08x,%08lx,%08lx,%08lx): returning %08lx\n", + heap, flags, (DWORD)ptr, size, (DWORD)(pArena + 1) ); + return (LPVOID)(pArena + 1); +} + + +/*********************************************************************** + * HeapCompact (KERNEL32.335) + * + * @unimplemented + */ +DWORD STDCALL RtlCompactHeap( HANDLE heap, DWORD flags ) +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return 0; +} + + +/*********************************************************************** + * HeapLock (KERNEL32.339) + * Attempts to acquire the critical section object for a specified heap. + * + * RETURNS + * TRUE: Success + * FALSE: Failure + * + * @implemented + */ +BOOL STDCALL RtlLockHeap( + HANDLE heap /* [in] Handle of heap to lock for exclusive access */ +) +{ + HEAP *heapPtr = HEAP_GetPtr( heap ); + if (!heapPtr) + return FALSE; + RtlEnterCriticalSection( &heapPtr->critSection ); + return TRUE; +} + + +/*********************************************************************** + * HeapUnlock (KERNEL32.342) + * Releases ownership of the critical section object. + * + * RETURNS + * TRUE: Success + * FALSE: Failure + * + * @implemented + */ +BOOL STDCALL RtlUnlockHeap( + HANDLE heap /* [in] Handle to the heap to unlock */ +) +{ + HEAP *heapPtr = HEAP_GetPtr( heap ); + if (!heapPtr) + return FALSE; + RtlLeaveCriticalSection( &heapPtr->critSection ); + return TRUE; +} + + +/*********************************************************************** + * HeapSize (KERNEL32.341) + * RETURNS + * Size in bytes of allocated memory + * 0xffffffff: Failure + * + * @implemented + */ +DWORD STDCALL RtlSizeHeap( + HANDLE heap, /* [in] Handle of heap */ + DWORD flags, /* [in] Heap size control flags */ + LPVOID ptr /* [in] Address of memory to return size for */ +) +{ + DWORD ret; + HEAP *heapPtr = HEAP_GetPtr( heap ); + + if (!heapPtr) + return FALSE; + flags &= HEAP_NO_SERIALIZE; + flags |= heapPtr->flags; + if (!(flags & HEAP_NO_SERIALIZE)) + RtlEnterCriticalSection( &heapPtr->critSection ); + if (!HEAP_IsRealArena( heap, HEAP_NO_SERIALIZE, ptr, QUIET )) + { + SetLastError( ERROR_INVALID_PARAMETER ); + ret = 0xffffffff; + } + else + { + ARENA_INUSE *pArena = (ARENA_INUSE *)ptr - 1; + ret = pArena->size & ARENA_SIZE_MASK; + } + if (!(flags & HEAP_NO_SERIALIZE)) + RtlLeaveCriticalSection( &heapPtr->critSection ); + + TRACE("(%08x,%08lx,%08lx): returning %08lx\n", + heap, flags, (DWORD)ptr, ret ); + return ret; +} + + +/*********************************************************************** + * HeapValidate (KERNEL32.343) + * Validates a specified heap. + * + * NOTES + * Flags is ignored. + * + * RETURNS + * TRUE: Success + * FALSE: Failure + * + * @implemented + */ +BOOL STDCALL RtlValidateHeap( + HANDLE heap, /* [in] Handle to the heap */ + DWORD flags, /* [in] Bit flags that control access during operation */ + PVOID block /* [in] Optional pointer to memory block to validate */ +) +{ + + HEAP *heapPtr = HEAP_GetPtr( heap ); + if (!heapPtr) + return FALSE; + return HEAP_IsRealArena( heapPtr, flags, block, QUIET ); +} + + +/*********************************************************************** + * HeapWalk (KERNEL32.344) + * Enumerates the memory blocks in a specified heap. + * See HEAP_Dump() for info on heap structure. + * + * TODO + * - handling of PROCESS_HEAP_ENTRY_MOVEABLE and + * PROCESS_HEAP_ENTRY_DDESHARE (needs heap.c support) + * + * RETURNS + * TRUE: Success + * FALSE: Failure + */ +#if 0 +BOOL STDCALL HeapWalk( + HANDLE heap, /* [in] Handle to heap to enumerate */ + LPPROCESS_HEAP_ENTRY entry /* [out] Pointer to structure of enumeration info */ +) +{ + HEAP *heapPtr = HEAP_GetPtr(heap); + SUBHEAP *sub, *currentheap = NULL; + BOOL ret = FALSE; + char *ptr; + int region_index = 0; + + if (!heapPtr || !entry) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) + RtlEnterCriticalSection( &heapPtr->critSection ); + + /* set ptr to the next arena to be examined */ + + if (!entry->lpData) /* first call (init) ? */ + { + TRACE("begin walking of heap 0x%08x.\n", heap); + /*HEAP_Dump(heapPtr);*/ + currentheap = &heapPtr->subheap; + ptr = (char*)currentheap + currentheap->headerSize; + } + else + { + ptr = entry->lpData; + sub = &heapPtr->subheap; + while (sub) + { + if (((char *)ptr >= (char *)sub) && + ((char *)ptr < (char *)sub + sub->size)) + { + currentheap = sub; + break; + } + sub = sub->next; + region_index++; + } + if (currentheap == NULL) + { + ERR("no matching subheap found, shouldn't happen !\n"); + SetLastError(ERROR_NO_MORE_ITEMS); + goto HW_end; + } + + ptr += entry->cbData; /* point to next arena */ + if (ptr > (char *)currentheap + currentheap->size - 1) + { /* proceed with next subheap */ + if (!(currentheap = currentheap->next)) + { /* successfully finished */ + TRACE("end reached.\n"); + SetLastError(ERROR_NO_MORE_ITEMS); + goto HW_end; + } + ptr = (char*)currentheap + currentheap->headerSize; + } + } + + entry->wFlags = 0; + if (*(DWORD *)ptr & ARENA_FLAG_FREE) + { + ARENA_FREE *pArena = (ARENA_FREE *)ptr; + + /*TRACE("free, magic: %04x\n", pArena->magic);*/ + + entry->lpData = pArena + 1; + entry->cbData = pArena->size & ARENA_SIZE_MASK; + entry->cbOverhead = sizeof(ARENA_FREE); + entry->wFlags = PROCESS_HEAP_UNCOMMITTED_RANGE; + } + else + { + ARENA_INUSE *pArena = (ARENA_INUSE *)ptr; + + /*TRACE("busy, magic: %04x\n", pArena->magic);*/ + + entry->lpData = pArena + 1; + entry->cbData = pArena->size & ARENA_SIZE_MASK; + entry->cbOverhead = sizeof(ARENA_INUSE); + entry->wFlags = PROCESS_HEAP_ENTRY_BUSY; + /* FIXME: can't handle PROCESS_HEAP_ENTRY_MOVEABLE + and PROCESS_HEAP_ENTRY_DDESHARE yet */ + } + + entry->iRegionIndex = region_index; + + /* first element of heap ? */ + if (ptr == (char *)(currentheap + currentheap->headerSize)) + { + entry->wFlags |= PROCESS_HEAP_REGION; + entry->Foo.Region.dwCommittedSize = currentheap->commitSize; + entry->Foo.Region.dwUnCommittedSize = + currentheap->size - currentheap->commitSize; + entry->Foo.Region.lpFirstBlock = /* first valid block */ + currentheap + currentheap->headerSize; + entry->Foo.Region.lpLastBlock = /* first invalid block */ + currentheap + currentheap->size; + } + ret = TRUE; + +HW_end: + if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) + RtlLeaveCriticalSection( &heapPtr->critSection ); + + return ret; +} +#endif + +VOID +RtlInitializeHeapManager(VOID) +{ + PPEB Peb; + + Peb = NtCurrentPeb(); + + Peb->NumberOfHeaps = 0; + Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(HANDLE); + Peb->ProcessHeaps = (PVOID)Peb + sizeof(PEB); + + RtlInitializeCriticalSection(&RtlpProcessHeapsListLock); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlEnumProcessHeaps(DWORD STDCALL_FUNC(*func)(void*,LONG), + LONG lParam) +{ + NTSTATUS Status = STATUS_SUCCESS; + ULONG i; + + RtlEnterCriticalSection(&RtlpProcessHeapsListLock); + + for (i = 0; i < NtCurrentPeb()->NumberOfHeaps; i++) + { + Status = func(NtCurrentPeb()->ProcessHeaps[i],lParam); + if (!NT_SUCCESS(Status)) + break; + } + + RtlLeaveCriticalSection(&RtlpProcessHeapsListLock); + + return Status; +} + + +/* + * @implemented + */ +ULONG STDCALL +RtlGetProcessHeaps(ULONG HeapCount, + HANDLE *HeapArray) +{ + ULONG Result = 0; + + RtlEnterCriticalSection(&RtlpProcessHeapsListLock); + + if (NtCurrentPeb()->NumberOfHeaps <= HeapCount) + { + Result = NtCurrentPeb()->NumberOfHeaps; + memmove(HeapArray, + NtCurrentPeb()->ProcessHeaps, + Result * sizeof(HANDLE)); + } + + RtlLeaveCriticalSection (&RtlpProcessHeapsListLock); + + return Result; +} + + +/* + * @implemented + */ +BOOLEAN STDCALL +RtlValidateProcessHeaps(VOID) +{ + HANDLE Heaps[128]; + BOOLEAN Result = TRUE; + ULONG HeapCount; + ULONG i; + + HeapCount = RtlGetProcessHeaps(128, Heaps); + for (i = 0; i < HeapCount; i++) + { + if (!RtlValidateHeap(Heaps[i], 0, NULL)) + Result = FALSE; + } + + return Result; +} + +/* EOF */ diff --git a/reactos/lib/rtl/largeint.c b/reactos/lib/rtl/largeint.c new file mode 100644 index 00000000000..b520bb08cc0 --- /dev/null +++ b/reactos/lib/rtl/largeint.c @@ -0,0 +1,356 @@ +/* $Id: largeint.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: lib/rtl/largeint.c + * PURPOSE: Large integer operations + * UPDATE HISTORY: + * Created 22/05/98 + * 08/30/98 RJJ Implemented several functions + */ + +/* INCLUDES *****************************************************************/ + +#include + +#define NDEBUG +#include + + +/* FUNCTIONS *****************************************************************/ + +/* + * @implemented + */ +LARGE_INTEGER +STDCALL +RtlConvertLongToLargeInteger ( + LONG SignedInteger +) +{ + LARGE_INTEGER RC; + + RC.QuadPart = SignedInteger; + + return RC; +} + +/* + * @implemented + */ +LARGE_INTEGER +STDCALL +RtlConvertUlongToLargeInteger ( + ULONG UnsignedInteger +) +{ + LARGE_INTEGER RC; + + RC.QuadPart = UnsignedInteger; + + return RC; +} + +/* + * @implemented + */ +LARGE_INTEGER +STDCALL +RtlEnlargedIntegerMultiply ( + LONG Multiplicand, + LONG Multiplier +) +{ + LARGE_INTEGER RC; + + RC.QuadPart = (LONGLONG) Multiplicand * Multiplier; + + return RC; +} + +/* + * @implemented + */ +ULONG +STDCALL +RtlEnlargedUnsignedDivide ( + ULARGE_INTEGER Dividend, + ULONG Divisor, + PULONG Remainder +) +{ + if (Remainder) + *Remainder = Dividend.QuadPart % Divisor; + + return (ULONG)(Dividend.QuadPart / Divisor); +} + +/* + * @implemented + */ +LARGE_INTEGER +STDCALL +RtlEnlargedUnsignedMultiply ( + ULONG Multiplicand, + ULONG Multiplier +) +{ + LARGE_INTEGER RC; + + RC.QuadPart = (ULONGLONG) Multiplicand * Multiplier; + + return RC; +} + +/* + * @implemented + */ +LARGE_INTEGER +STDCALL +RtlExtendedIntegerMultiply ( + LARGE_INTEGER Multiplicand, + LONG Multiplier +) +{ + LARGE_INTEGER RC; + + RC.QuadPart = Multiplicand.QuadPart * Multiplier; + + return RC; +} + +/* + * @implemented + */ +LARGE_INTEGER +STDCALL +RtlExtendedLargeIntegerDivide ( + LARGE_INTEGER Dividend, + ULONG Divisor, + PULONG Remainder +) +{ + LARGE_INTEGER RC; + + if (Remainder) + *Remainder = Dividend.QuadPart % Divisor; + + RC.QuadPart = Dividend.QuadPart / Divisor; + + return RC; +} + + +/****************************************************************************** + * RtlExtendedMagicDivide + * + * Allows replacing a division by a longlong constant with a multiplication by + * the inverse constant. + * + * RETURNS + * (Dividend * MagicDivisor) >> (64 + ShiftCount) + * + * NOTES + * If the divisor of a division is constant, the constants MagicDivisor and + * shift must be chosen such that + * MagicDivisor = 2^(64 + ShiftCount) / Divisor. + * + * Then we have RtlExtendedMagicDivide(Dividend,MagicDivisor,ShiftCount) == + * Dividend * MagicDivisor / 2^(64 + ShiftCount) == Dividend / Divisor. + * + * The Parameter MagicDivisor although defined as LONGLONG is used as + * ULONGLONG. + */ + +#define LOWER_32(A) ((A) & 0xffffffff) +#define UPPER_32(A) ((A) >> 32) + +/* + * @implemented + */ +LARGE_INTEGER STDCALL +RtlExtendedMagicDivide (LARGE_INTEGER Dividend, + LARGE_INTEGER MagicDivisor, + CCHAR ShiftCount) +{ + ULONGLONG dividend_high; + ULONGLONG dividend_low; + ULONGLONG inverse_divisor_high; + ULONGLONG inverse_divisor_low; + ULONGLONG ah_bl; + ULONGLONG al_bh; + LARGE_INTEGER result; + BOOLEAN positive; + + if (Dividend.QuadPart < 0) + { + dividend_high = UPPER_32((ULONGLONG) -Dividend.QuadPart); + dividend_low = LOWER_32((ULONGLONG) -Dividend.QuadPart); + positive = FALSE; + } + else + { + dividend_high = UPPER_32((ULONGLONG) Dividend.QuadPart); + dividend_low = LOWER_32((ULONGLONG) Dividend.QuadPart); + positive = TRUE; + } + inverse_divisor_high = UPPER_32((ULONGLONG) MagicDivisor.QuadPart); + inverse_divisor_low = LOWER_32((ULONGLONG) MagicDivisor.QuadPart); + + ah_bl = dividend_high * inverse_divisor_low; + al_bh = dividend_low * inverse_divisor_high; + + result.QuadPart = + (LONGLONG) ((dividend_high * inverse_divisor_high + + UPPER_32(ah_bl) + + UPPER_32(al_bh) + + UPPER_32(LOWER_32(ah_bl) + LOWER_32(al_bh) + + UPPER_32(dividend_low * inverse_divisor_low))) >> ShiftCount); + if (!positive) + { + result.QuadPart = -result.QuadPart; + } + + return result; +} + + +/* + * @implemented + */ +LARGE_INTEGER +STDCALL +RtlLargeIntegerAdd ( + LARGE_INTEGER Addend1, + LARGE_INTEGER Addend2 +) +{ + LARGE_INTEGER RC; + + RC.QuadPart = Addend1.QuadPart + Addend2.QuadPart; + + return RC; +} + +/* + * @implemented + */ +LARGE_INTEGER +STDCALL +RtlLargeIntegerArithmeticShift ( + LARGE_INTEGER LargeInteger, + CCHAR ShiftCount +) +{ + LARGE_INTEGER RC; + CHAR Shift; + + Shift = ShiftCount % 64; + + if (Shift < 32) + { + RC.QuadPart = LargeInteger.QuadPart >> Shift; + } + else + { + /* copy the sign bit */ + RC.u.HighPart |= (LargeInteger.u.HighPart & 0x80000000); + RC.u.LowPart = LargeInteger.u.HighPart >> Shift; + } + + return RC; +} + +/* + * @implemented + */ +LARGE_INTEGER +STDCALL +RtlLargeIntegerDivide ( + LARGE_INTEGER Dividend, + LARGE_INTEGER Divisor, + PLARGE_INTEGER Remainder +) +{ + LARGE_INTEGER RC; + + if (Remainder) + Remainder->QuadPart = Dividend.QuadPart % Divisor.QuadPart; + + RC.QuadPart = Dividend.QuadPart / Divisor.QuadPart; + + return RC; +} + +/* + * @implemented + */ +LARGE_INTEGER +STDCALL +RtlLargeIntegerNegate ( + LARGE_INTEGER Subtrahend +) +{ + LARGE_INTEGER RC; + + RC.QuadPart = - Subtrahend.QuadPart; + + return RC; +} + +/* + * @implemented + */ +LARGE_INTEGER +STDCALL +RtlLargeIntegerShiftLeft ( + LARGE_INTEGER LargeInteger, + CCHAR ShiftCount +) +{ + LARGE_INTEGER RC; + CCHAR Shift; + + Shift = ShiftCount % 64; + RC.QuadPart = LargeInteger.QuadPart << Shift; + + return RC; +} + +/* + * @implemented + */ +LARGE_INTEGER +STDCALL +RtlLargeIntegerShiftRight ( + LARGE_INTEGER LargeInteger, + CCHAR ShiftCount +) +{ + LARGE_INTEGER RC; + CCHAR Shift; + + Shift = ShiftCount % 64; + RC.QuadPart = LargeInteger.QuadPart >> Shift; + + return RC; +} + +/* + * @implemented + */ +LARGE_INTEGER +STDCALL +RtlLargeIntegerSubtract ( + LARGE_INTEGER Minuend, + LARGE_INTEGER Subtrahend +) +{ + LARGE_INTEGER RC; + + RC.QuadPart = Minuend.QuadPart - Subtrahend.QuadPart; + + return RC; +} + +/* EOF */ diff --git a/reactos/lib/rtl/luid.c b/reactos/lib/rtl/luid.c new file mode 100644 index 00000000000..3bf8e6e170d --- /dev/null +++ b/reactos/lib/rtl/luid.c @@ -0,0 +1,60 @@ +/* $Id: luid.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PURPOSE: Locally unique identifier (LUID) helper functions + * FILE: lib/rtl/luid.c + * PROGRAMER: Eric Kohl + * REVISION HISTORY: + * 15/04/2000: Created + */ + +/* INCLUDES *****************************************************************/ + +#include + +#define NDEBUG +#include + +/* FUNCTIONS *****************************************************************/ + +VOID STDCALL +RtlCopyLuid(PLUID LuidDest, + PLUID LuidSrc) +{ + LuidDest->LowPart = LuidSrc->LowPart; + LuidDest->HighPart = LuidSrc->HighPart; +} + + +/* + * @implemented + */ +VOID STDCALL +RtlCopyLuidAndAttributesArray(ULONG Count, + PLUID_AND_ATTRIBUTES Src, + PLUID_AND_ATTRIBUTES Dest) +{ + ULONG i; + + for (i = 0; i < Count; i++) + { + RtlCopyMemory(&Dest[i], + &Src[i], + sizeof(LUID_AND_ATTRIBUTES)); + } +} + + +/* + * @implemented + */ +BOOLEAN STDCALL +RtlEqualLuid(PLUID Luid1, + PLUID Luid2) +{ + return (Luid1->LowPart == Luid2->LowPart && + Luid1->HighPart == Luid2->HighPart); +} + +/* EOF */ diff --git a/reactos/lib/rtl/makefile b/reactos/lib/rtl/makefile new file mode 100644 index 00000000000..dc94c041136 --- /dev/null +++ b/reactos/lib/rtl/makefile @@ -0,0 +1,49 @@ + +PATH_TO_TOP = ../.. + +TARGET_TYPE = library + +TARGET_NAME = rtl + +include $(PATH_TO_TOP)/config + +TARGET_CFLAGS = -Wall -Werror + +# require os code to explicitly request A/W version of structs/functions +TARGET_CFLAGS += -D_DISABLE_TIDENTS + +TARGET_OBJECTS = \ + acl.o \ + compress.o \ + dos8dot3.o \ + env.o \ + error.o \ + heap.o \ + largeint.o \ + luid.o \ + mem.o \ + nls.o \ + random.o \ + sd.o \ + security.o \ + sid.o \ + time.o \ + timezone.o \ + unicode.o \ + version.o + +# atom +# registry + + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk + +DEP_OBJECTS := $(TARGET_OBJECTS) + +TARGET_CLEAN = $(DEP_FILES) + +include $(PATH_TO_TOP)/tools/depend.mk + +# EOF diff --git a/reactos/lib/rtl/mem.c b/reactos/lib/rtl/mem.c new file mode 100644 index 00000000000..a87a87ad337 --- /dev/null +++ b/reactos/lib/rtl/mem.c @@ -0,0 +1,231 @@ + +/* $Id: mem.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: lib/rtl/mem.c + * PURPOSE: Memory functions + * PROGRAMMER: David Welch (welch@mcmail.com) + * UPDATE HISTORY: + * Created 22/05/98 + */ + +/* INCLUDES *****************************************************************/ + +#include +#include + +#define NDEBUG +#include + + + + +/* FUNCTIONS *****************************************************************/ + +/****************************************************************************** + * RtlCompareMemory [NTDLL.@] + * + * Compare one block of memory with another + * + * PARAMS + * Source1 [I] Source block + * Source2 [I] Block to compare to Source1 + * Length [I] Number of bytes to fill + * + * RETURNS + * The length of the first byte at which Source1 and Source2 differ, or Length + * if they are the same. + * + * @implemented + */ +ULONG +STDCALL +RtlCompareMemory(PVOID Source1, + PVOID Source2, + ULONG Length) +{ + SIZE_T i; + for(i=0; (i 0) + { + *Dest = Fill; + Dest++; + Count--; + } +} + + + +/* + * @implemented + */ +VOID +STDCALL +RtlMoveMemory ( + PVOID Destination, + CONST VOID * Source, + ULONG Length +) +{ + memmove ( + Destination, + Source, + Length + ); +} + + +/* + * @implemented + */ +VOID +STDCALL +RtlZeroMemory ( + PVOID Destination, + ULONG Length +) +{ + RtlFillMemory ( + Destination, + Length, + 0 + ); +} + + +/************************************************************************* + * RtlUshortByteSwap + * + * Swap the bytes of an unsigned short value. + * + * NOTES + * Based on the inline versions in Wine winternl.h + * + * @implemented + */ +USHORT FASTCALL +RtlUshortByteSwap (IN USHORT Source) +{ + return (Source >> 8) | (Source << 8); +} + + + +/************************************************************************* + * RtlUlongByteSwap [NTDLL.@] + * + * Swap the bytes of an unsigned int value. + * + * NOTES + * Based on the inline versions in Wine winternl.h + * + * @implemented + */ +ULONG +FASTCALL +RtlUlongByteSwap( + IN ULONG Source +) +{ +#if defined(__i386__) && defined(__GNUC__) + ULONG ret; +__asm__("bswap %0" : "=r" (ret) : "0" (Source) ); + return ret; +#else + + return ((ULONG)RtlUshortByteSwap((USHORT)Source) << 16) | RtlUshortByteSwap((USHORT)(Source >> 16)); +#endif +} + + +/************************************************************************* + * RtlUlonglongByteSwap + * + * Swap the bytes of an unsigned long long value. + * + * PARAMS + * i [I] Value to swap bytes of + * + * RETURNS + * The value with its bytes swapped. + * + * @implemented + */ +ULONGLONG FASTCALL +RtlUlonglongByteSwap (IN ULONGLONG Source) +{ + return ((ULONGLONG) RtlUlongByteSwap (Source) << 32) | RtlUlongByteSwap (Source>>32); +} + + +/* EOF */ diff --git a/reactos/lib/rtl/nls.c b/reactos/lib/rtl/nls.c new file mode 100644 index 00000000000..2b926350e52 --- /dev/null +++ b/reactos/lib/rtl/nls.c @@ -0,0 +1,754 @@ +/* $Id: nls.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: lib/rtl/nls.c + * PURPOSE: National Language Support (NLS) functions + * UPDATE HISTORY: + * 20/08/99 Created by Emanuele Aliberti + * 10/11/99 Added translation functions. + * + * TODO: + * 1) Add multi-byte translation code. + */ + + +#include + +#define NDEBUG +#include + +/* GLOBALS *******************************************************************/ + +PUSHORT NlsUnicodeUpcaseTable = NULL; +PUSHORT NlsUnicodeLowercaseTable = NULL; + +USHORT NlsAnsiCodePage = 0; /* exported */ +BOOLEAN NlsMbCodePageTag = FALSE; /* exported */ +PWCHAR NlsAnsiToUnicodeTable = NULL; +PCHAR NlsUnicodeToAnsiTable = NULL; +PWCHAR NlsDbcsUnicodeToAnsiTable = NULL; +PUSHORT NlsLeadByteInfo = NULL; /* exported */ + + +USHORT NlsOemCodePage = 0; +BOOLEAN NlsMbOemCodePageTag = FALSE; /* exported */ +PWCHAR NlsOemToUnicodeTable = NULL; +PCHAR NlsUnicodeToOemTable =NULL; +PWCHAR NlsDbcsUnicodeToOemTable = NULL; +PUSHORT NlsOemLeadByteInfo = NULL; /* exported */ + + + + +#define INIT_FUNCTION + +/* FUNCTIONS *****************************************************************/ + + + + + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlCustomCPToUnicodeN(IN PCPTABLEINFO CustomCP, + PWCHAR UnicodeString, + ULONG UnicodeSize, + PULONG ResultSize, + PCHAR CustomString, + ULONG CustomSize) +{ + ULONG Size = 0; + ULONG i; + + if (CustomCP->DBCSCodePage == 0) + { + /* single-byte code page */ + if (CustomSize > (UnicodeSize / sizeof(WCHAR))) + Size = UnicodeSize / sizeof(WCHAR); + else + Size = CustomSize; + + if (ResultSize != NULL) + *ResultSize = Size * sizeof(WCHAR); + + for (i = 0; i < Size; i++) + { + *UnicodeString = CustomCP->MultiByteTable[(UCHAR)*CustomString]; + UnicodeString++; + CustomString++; + } + } + else + { + /* multi-byte code page */ + /* FIXME */ + assert(FALSE); + } + + return(STATUS_SUCCESS); +} + + + +WCHAR STDCALL +RtlDowncaseUnicodeChar (IN WCHAR Source) +{ + USHORT Offset; + + if (Source < L'A') + return Source; + + if (Source <= L'Z') + return Source + (L'a' - L'A'); + + if (Source < 0x80) + return Source; + + Offset = ((USHORT)Source >> 8); + DPRINT("Offset: %hx\n", Offset); + + Offset = NlsUnicodeLowercaseTable[Offset]; + DPRINT("Offset: %hx\n", Offset); + + Offset += (((USHORT)Source & 0x00F0) >> 4); + DPRINT("Offset: %hx\n", Offset); + + Offset = NlsUnicodeLowercaseTable[Offset]; + DPRINT("Offset: %hx\n", Offset); + + Offset += ((USHORT)Source & 0x000F); + DPRINT("Offset: %hx\n", Offset); + + Offset = NlsUnicodeLowercaseTable[Offset]; + DPRINT("Offset: %hx\n", Offset); + + DPRINT("Result: %hx\n", Source + (SHORT)Offset); + + return Source + (SHORT)Offset; +} + + + + +/* + * @implemented + */ +VOID STDCALL +RtlGetDefaultCodePage(OUT PUSHORT AnsiCodePage, + OUT PUSHORT OemCodePage) +{ + *AnsiCodePage = NlsAnsiCodePage; + *OemCodePage = NlsOemCodePage; +} + + + + +/* + * @implemented + */ +VOID STDCALL +RtlInitCodePageTable(IN PUSHORT TableBase, + OUT PCPTABLEINFO CodePageTable) +{ + PNLS_FILE_HEADER NlsFileHeader; + PUSHORT Ptr; + USHORT Offset; + + DPRINT("RtlInitCodePageTable() called\n"); + + NlsFileHeader = (PNLS_FILE_HEADER)TableBase; + + CodePageTable->CodePage = NlsFileHeader->CodePage; + CodePageTable->MaximumCharacterSize = NlsFileHeader->MaximumCharacterSize; + CodePageTable->DefaultChar = NlsFileHeader->DefaultChar; + CodePageTable->UniDefaultChar = NlsFileHeader->UniDefaultChar; + CodePageTable->TransDefaultChar = NlsFileHeader->TransDefaultChar; + CodePageTable->TransUniDefaultChar = NlsFileHeader->TransUniDefaultChar; + + RtlCopyMemory(&CodePageTable->LeadByte, + &NlsFileHeader->LeadByte, + MAXIMUM_LEADBYTES); + + /* Set Pointer to start of multi byte table */ + Ptr = (PUSHORT)((ULONG_PTR)TableBase + 2 * NlsFileHeader->HeaderSize); + + /* Get offset to the wide char table */ + Offset = (USHORT)(*Ptr++) + NlsFileHeader->HeaderSize + 1; + + /* Set pointer to the multi byte table */ + CodePageTable->MultiByteTable = Ptr; + + /* Skip ANSI and OEM table */ + Ptr += 256; + if (*Ptr++) + Ptr += 256; + + /* Set pointer to DBCS ranges */ + CodePageTable->DBCSRanges = (PUSHORT)Ptr; + + if (*Ptr > 0) + { + CodePageTable->DBCSCodePage = 1; + CodePageTable->DBCSOffsets = (PUSHORT)++Ptr; + } + else + { + CodePageTable->DBCSCodePage = 0; + CodePageTable->DBCSOffsets = 0; + } + + CodePageTable->WideCharTable = (PVOID)((ULONG_PTR)TableBase + 2 * Offset); +} + + + + +/* + * @implemented + */ +VOID STDCALL +RtlInitNlsTables(IN PUSHORT AnsiTableBase, + IN PUSHORT OemTableBase, + IN PUSHORT CaseTableBase, + OUT PNLSTABLEINFO NlsTable) +{ + DPRINT("RtlInitNlsTables()called\n"); + + if (AnsiTableBase == NULL || + OemTableBase == NULL || + CaseTableBase == NULL) + return; + + RtlInitCodePageTable (AnsiTableBase, + &NlsTable->AnsiTableInfo); + + RtlInitCodePageTable (OemTableBase, + &NlsTable->OemTableInfo); + + NlsTable->UpperCaseTable = (PUSHORT)CaseTableBase + 2; + NlsTable->LowerCaseTable = (PUSHORT)CaseTableBase + *((PUSHORT)CaseTableBase + 1) + 2; +} + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlMultiByteToUnicodeN( + IN PWCHAR UnicodeString, + IN ULONG UnicodeSize, + IN PULONG ResultSize, + IN PCHAR MbString, + IN ULONG MbSize) +{ + ULONG Size = 0; + ULONG i; + + if (NlsMbCodePageTag == FALSE) + { + /* single-byte code page */ + if (MbSize > (UnicodeSize / sizeof(WCHAR))) + Size = UnicodeSize / sizeof(WCHAR); + else + Size = MbSize; + + if (ResultSize != NULL) + *ResultSize = Size * sizeof(WCHAR); + + for (i = 0; i < Size; i++) + UnicodeString[i] = NlsAnsiToUnicodeTable[(UCHAR)MbString[i]]; + } + else + { + /* multi-byte code page */ + /* FIXME */ + assert(FALSE); + } + + return(STATUS_SUCCESS); +} + + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlMultiByteToUnicodeSize(PULONG UnicodeSize, + PCHAR MbString, + ULONG MbSize) +{ + ULONG Length; + + if (NlsMbCodePageTag == FALSE) + { + /* single-byte code page */ + *UnicodeSize = MbSize * sizeof (WCHAR); + } + else + { + /* multi-byte code page */ + for (Length = 0; MbSize; MbSize--, MbString++, Length++) + { + if (NlsLeadByteInfo[(UCHAR)*MbString] != 0) + { + if (!--MbSize) + break; /* partial char, ignore it */ + MbString++; + } + } + + *UnicodeSize = Length * sizeof(WCHAR); + } + + return STATUS_SUCCESS; +} + + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlOemToUnicodeN (PWCHAR UnicodeString, + ULONG UnicodeSize, + PULONG ResultSize, + PCHAR OemString, + ULONG OemSize) +{ + ULONG Size = 0; + ULONG i; + + if (NlsMbOemCodePageTag == FALSE) + { + /* single-byte code page */ + if (OemSize > (UnicodeSize / sizeof(WCHAR))) + Size = UnicodeSize / sizeof(WCHAR); + else + Size = OemSize; + + if (ResultSize != NULL) + *ResultSize = Size * sizeof(WCHAR); + + for (i = 0; i < Size; i++) + { + *UnicodeString = NlsOemToUnicodeTable[(INT)*OemString]; + UnicodeString++; + OemString++; + } + } + else + { + /* multi-byte code page */ + /* FIXME */ + assert(FALSE); + } + + return STATUS_SUCCESS; +} + + + +/* + * @implemented + */ +VOID STDCALL +RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable) +{ + DPRINT("RtlResetRtlTranslations() called\n"); + + /* Set ANSI data */ + NlsAnsiToUnicodeTable = NlsTable->AnsiTableInfo.MultiByteTable; + NlsUnicodeToAnsiTable = NlsTable->AnsiTableInfo.WideCharTable; + NlsDbcsUnicodeToAnsiTable = (PWCHAR)NlsTable->AnsiTableInfo.WideCharTable; + NlsMbCodePageTag = (NlsTable->AnsiTableInfo.DBCSCodePage != 0); + NlsLeadByteInfo = NlsTable->AnsiTableInfo.DBCSOffsets; + NlsAnsiCodePage = NlsTable->AnsiTableInfo.CodePage; + DPRINT("Ansi codepage %hu\n", NlsAnsiCodePage); + + /* Set OEM data */ + NlsOemToUnicodeTable = NlsTable->OemTableInfo.MultiByteTable; + NlsUnicodeToOemTable = NlsTable->OemTableInfo.WideCharTable; + NlsDbcsUnicodeToOemTable = (PWCHAR)NlsTable->OemTableInfo.WideCharTable; + NlsMbOemCodePageTag = (NlsTable->OemTableInfo.DBCSCodePage != 0); + NlsOemLeadByteInfo = NlsTable->OemTableInfo.DBCSOffsets; + NlsOemCodePage = NlsTable->OemTableInfo.CodePage; + DPRINT("Oem codepage %hu\n", NlsOemCodePage); + + /* Set Unicode case map data */ + NlsUnicodeUpcaseTable = NlsTable->UpperCaseTable; + NlsUnicodeLowercaseTable = NlsTable->LowerCaseTable; +} + + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP, + PCHAR CustomString, + ULONG CustomSize, + PULONG ResultSize, + PWCHAR UnicodeString, + ULONG UnicodeSize) +{ + ULONG Size = 0; + ULONG i; + + if (CustomCP->DBCSCodePage == 0) + { + /* single-byte code page */ + if (UnicodeSize > (CustomSize * sizeof(WCHAR))) + Size = CustomSize; + else + Size = UnicodeSize / sizeof(WCHAR); + + if (ResultSize != NULL) + *ResultSize = Size; + + for (i = 0; i < Size; i++) + { + *CustomString = ((PCHAR)CustomCP->WideCharTable)[*UnicodeString]; + CustomString++; + UnicodeString++; + } + } + else + { + /* multi-byte code page */ + /* FIXME */ + assert(FALSE); + } + + return STATUS_SUCCESS; +} + + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlUnicodeToMultiByteN (PCHAR MbString, + ULONG MbSize, + PULONG ResultSize, + PWCHAR UnicodeString, + ULONG UnicodeSize) +{ + ULONG Size = 0; + ULONG i; + + if (NlsMbCodePageTag == FALSE) + { + /* single-byte code page */ + if (UnicodeSize > (MbSize * sizeof(WCHAR))) + Size = MbSize; + else + Size = UnicodeSize / sizeof(WCHAR); + + if (ResultSize != NULL) + *ResultSize = Size; + + for (i = 0; i < Size; i++) + { + *MbString = NlsUnicodeToAnsiTable[*UnicodeString]; + MbString++; + UnicodeString++; + } + } + else + { + /* multi-byte code page */ + /* FIXME */ + assert(FALSE); + } + + return STATUS_SUCCESS; +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlUnicodeToMultiByteSize(PULONG MbSize, + PWCHAR UnicodeString, + ULONG UnicodeSize) +{ + ULONG UnicodeLength; + ULONG MbLength; + + if (NlsMbCodePageTag == FALSE) + { + /* single-byte code page */ + *MbSize = UnicodeSize / sizeof (WCHAR); + } + else + { + /* multi-byte code page */ + UnicodeLength = UnicodeSize / sizeof(WCHAR); + MbLength = 0; + while (UnicodeLength > 0) + { + if (NlsLeadByteInfo[(USHORT)*UnicodeString] & 0xff00) + MbLength++; + + MbLength++; + UnicodeLength--; + UnicodeString++; + } + + *MbSize = MbLength; + } + + return(STATUS_SUCCESS); +} + + + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlUnicodeToOemN (PCHAR OemString, + ULONG OemSize, + PULONG ResultSize, + PWCHAR UnicodeString, + ULONG UnicodeSize) +{ + ULONG Size = 0; + ULONG i; + + if (NlsMbOemCodePageTag == FALSE) + { + /* single-byte code page */ + if (UnicodeSize > (OemSize * sizeof(WCHAR))) + Size = OemSize; + else + Size = UnicodeSize / sizeof(WCHAR); + + if (ResultSize != NULL) + *ResultSize = Size; + + for (i = 0; i < Size; i++) + { + *OemString = NlsUnicodeToOemTable[*UnicodeString]; + OemString++; + UnicodeString++; + } + } + else + { + /* multi-byte code page */ + /* FIXME */ + assert(FALSE); + } + + return STATUS_SUCCESS; +} + + + + +/* + * @implemented + */ +WCHAR STDCALL +RtlUpcaseUnicodeChar(IN WCHAR Source) +{ + USHORT Offset; + + if (Source < L'a') + return Source; + + if (Source <= L'z') + return (Source - (L'a' - L'A')); + + Offset = ((USHORT)Source >> 8); + Offset = NlsUnicodeUpcaseTable[Offset]; + + Offset += (((USHORT)Source & 0x00F0) >> 4); + Offset = NlsUnicodeUpcaseTable[Offset]; + + Offset += ((USHORT)Source & 0x000F); + Offset = NlsUnicodeUpcaseTable[Offset]; + + return Source + (SHORT)Offset; +} + + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlUpcaseUnicodeToCustomCPN (IN PCPTABLEINFO CustomCP, + PCHAR CustomString, + ULONG CustomSize, + PULONG ResultSize, + PWCHAR UnicodeString, + ULONG UnicodeSize) +{ + WCHAR UpcaseChar; + ULONG Size = 0; + ULONG i; + + if (CustomCP->DBCSCodePage == 0) + { + /* single-byte code page */ + if (UnicodeSize > (CustomSize * sizeof(WCHAR))) + Size = CustomSize; + else + Size = UnicodeSize / sizeof(WCHAR); + + if (ResultSize != NULL) + *ResultSize = Size; + + for (i = 0; i < Size; i++) + { + UpcaseChar = RtlUpcaseUnicodeChar(*UnicodeString); + *CustomString = ((PCHAR)CustomCP->WideCharTable)[UpcaseChar]; + CustomString++; + UnicodeString++; + } + } + else + { + /* multi-byte code page */ + /* FIXME */ + assert(FALSE); + } + + return STATUS_SUCCESS; +} + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlUpcaseUnicodeToMultiByteN (PCHAR MbString, + ULONG MbSize, + PULONG ResultSize, + PWCHAR UnicodeString, + ULONG UnicodeSize) +{ + WCHAR UpcaseChar; + ULONG Size = 0; + ULONG i; + + if (NlsMbCodePageTag == FALSE) + { + /* single-byte code page */ + if (UnicodeSize > (MbSize * sizeof(WCHAR))) + Size = MbSize; + else + Size = UnicodeSize / sizeof(WCHAR); + + if (ResultSize != NULL) + *ResultSize = Size; + + for (i = 0; i < Size; i++) + { + UpcaseChar = RtlUpcaseUnicodeChar(*UnicodeString); + *MbString = NlsUnicodeToAnsiTable[UpcaseChar]; + MbString++; + UnicodeString++; + } + } + else + { + /* multi-byte code page */ + /* FIXME */ + assert(FALSE); + } + + return STATUS_SUCCESS; +} + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlUpcaseUnicodeToOemN (PCHAR OemString, + ULONG OemSize, + PULONG ResultSize, + PWCHAR UnicodeString, + ULONG UnicodeSize) +{ + WCHAR UpcaseChar; + ULONG Size = 0; + ULONG i; + + if (NlsMbOemCodePageTag == FALSE) + { + /* single-byte code page */ + if (UnicodeSize > (OemSize * sizeof(WCHAR))) + Size = OemSize; + else + Size = UnicodeSize / sizeof(WCHAR); + + if (ResultSize != NULL) + *ResultSize = Size; + + for (i = 0; i < Size; i++) + { + UpcaseChar = RtlUpcaseUnicodeChar(*UnicodeString); + *OemString = NlsUnicodeToOemTable[UpcaseChar]; + OemString++; + UnicodeString++; + } + } + else + { + /* multi-byte code page */ + /* FIXME */ + assert(FALSE); + } + + return STATUS_SUCCESS; +} + + + +/* + * @unimplemented + */ +CHAR STDCALL +RtlUpperChar (IN CHAR Source) +{ + WCHAR Unicode; + CHAR Destination; + + if (NlsMbCodePageTag == FALSE) + { + /* single-byte code page */ + + /* ansi->unicode */ + Unicode = NlsAnsiToUnicodeTable[(UCHAR)Source]; + + /* upcase conversion */ + Unicode = RtlUpcaseUnicodeChar (Unicode); + + /* unicode -> ansi */ + Destination = NlsUnicodeToAnsiTable[(USHORT)Unicode]; + } + else + { + /* multi-byte code page */ + /* FIXME */ + Destination = Source; + } + + return Destination; +} + +/* EOF */ diff --git a/reactos/lib/rtl/random.c b/reactos/lib/rtl/random.c new file mode 100644 index 00000000000..9c34bbea847 --- /dev/null +++ b/reactos/lib/rtl/random.c @@ -0,0 +1,159 @@ +/* + * ReactOS kernel + * Copyright (C) 2003 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: random.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PURPOSE: Random number generator functions + * FILE: lib/rtl/random.c + */ + +/* INCLUDES *****************************************************************/ + +#define NTOS_MODE_USER +#include + +//#include + + +static ULONG SavedValue[128] = + { + 0x4c8bc0aa, 0x4c022957, 0x2232827a, 0x2f1e7626, /* 0 */ + 0x7f8bdafb, 0x5c37d02a, 0x0ab48f72, 0x2f0c4ffa, /* 4 */ + 0x290e1954, 0x6b635f23, 0x5d3885c0, 0x74b49ff8, /* 8 */ + 0x5155fa54, 0x6214ad3f, 0x111e9c29, 0x242a3a09, /* 12 */ + 0x75932ae1, 0x40ac432e, 0x54f7ba7a, 0x585ccbd5, /* 16 */ + 0x6df5c727, 0x0374dad1, 0x7112b3f1, 0x735fc311, /* 20 */ + 0x404331a9, 0x74d97781, 0x64495118, 0x323e04be, /* 24 */ + 0x5974b425, 0x4862e393, 0x62389c1d, 0x28a68b82, /* 28 */ + 0x0f95da37, 0x7a50bbc6, 0x09b0091c, 0x22cdb7b4, /* 32 */ + 0x4faaed26, 0x66417ccd, 0x189e4bfa, 0x1ce4e8dd, /* 36 */ + 0x5274c742, 0x3bdcf4dc, 0x2d94e907, 0x32eac016, /* 40 */ + 0x26d33ca3, 0x60415a8a, 0x31f57880, 0x68c8aa52, /* 44 */ + 0x23eb16da, 0x6204f4a1, 0x373927c1, 0x0d24eb7c, /* 48 */ + 0x06dd7379, 0x2b3be507, 0x0f9c55b1, 0x2c7925eb, /* 52 */ + 0x36d67c9a, 0x42f831d9, 0x5e3961cb, 0x65d637a8, /* 56 */ + 0x24bb3820, 0x4d08e33d, 0x2188754f, 0x147e409e, /* 60 */ + 0x6a9620a0, 0x62e26657, 0x7bd8ce81, 0x11da0abb, /* 64 */ + 0x5f9e7b50, 0x23e444b6, 0x25920c78, 0x5fc894f0, /* 68 */ + 0x5e338cbb, 0x404237fd, 0x1d60f80f, 0x320a1743, /* 72 */ + 0x76013d2b, 0x070294ee, 0x695e243b, 0x56b177fd, /* 76 */ + 0x752492e1, 0x6decd52f, 0x125f5219, 0x139d2e78, /* 80 */ + 0x1898d11e, 0x2f7ee785, 0x4db405d8, 0x1a028a35, /* 84 */ + 0x63f6f323, 0x1f6d0078, 0x307cfd67, 0x3f32a78a, /* 88 */ + 0x6980796c, 0x462b3d83, 0x34b639f2, 0x53fce379, /* 92 */ + 0x74ba50f4, 0x1abc2c4b, 0x5eeaeb8d, 0x335a7a0d, /* 96 */ + 0x3973dd20, 0x0462d66b, 0x159813ff, 0x1e4643fd, /* 100 */ + 0x06bc5c62, 0x3115e3fc, 0x09101613, 0x47af2515, /* 104 */ + 0x4f11ec54, 0x78b99911, 0x3db8dd44, 0x1ec10b9b, /* 108 */ + 0x5b5506ca, 0x773ce092, 0x567be81a, 0x5475b975, /* 112 */ + 0x7a2cde1a, 0x494536f5, 0x34737bb4, 0x76d9750b, /* 116 */ + 0x2a1f6232, 0x2e49644d, 0x7dddcbe7, 0x500cebdb, /* 120 */ + 0x619dab9e, 0x48c626fe, 0x1cda3193, 0x52dabe9d /* 124 */ + }; + + +/************************************************************************* + * RtlRandom [NTDLL.@] + * + * Generates a random number + * + * PARAMS + * Seed [O] The seed of the Random function + * + * RETURNS + * It returns a random number distributed over [0..MAXLONG-1]. + */ +ULONG STDCALL +RtlRandom (IN OUT PULONG Seed) +{ + ULONG Rand; + int Pos; + ULONG Result; + + Rand = (*Seed * 0x7fffffed + 0x7fffffc3) % 0x7fffffff; + *Seed = (Rand * 0x7fffffed + 0x7fffffc3) % 0x7fffffff; + Pos = *Seed & 0x7f; + Result = SavedValue[Pos]; + SavedValue[Pos] = Rand; + + return Result; +} + + + +/************************************************************************* + * RtlUniform [NTDLL.@] + * + * Generates an uniform random number + * + * PARAMS + * Seed [O] The seed of the Random function + * + * RETURNS + * It returns a random number uniformly distributed over [0..MAXLONG-1]. + * + * NOTES + * Generates an uniform random number using D.H. Lehmer's 1948 algorithm. + * In our case the algorithm is: + * + * Result = (*Seed * 0x7fffffed + 0x7fffffc3) % MAXLONG; + * + * *Seed = Result; + * + * DIFFERENCES + * The native documentation states that the random number is + * uniformly distributed over [0..MAXLONG]. In reality the native + * function and our function return a random number uniformly + * distributed over [0..MAXLONG-1]. + */ +ULONG STDCALL +RtlUniform (PULONG Seed) +{ + ULONG Result; + + /* + * Instead of the algorithm stated above, we use the algorithm + * below, which is totally equivalent (see the tests), but does + * not use a division and therefore is faster. + */ + Result = *Seed * 0xffffffed + 0x7fffffc3; + + if (Result == 0xffffffff || Result == 0x7ffffffe) + { + Result = (Result + 2) & MAXLONG; + } + else if (Result == 0x7fffffff) + { + Result = 0; + } + else if ((Result & 0x80000000) == 0) + { + Result = Result + (~Result & 1); + } + else + { + Result = (Result + (Result & 1)) & MAXLONG; + } + + *Seed = Result; + + return Result; +} +/* EOF */ diff --git a/reactos/lib/rtl/sd.c b/reactos/lib/rtl/sd.c new file mode 100644 index 00000000000..a7cce3c9288 --- /dev/null +++ b/reactos/lib/rtl/sd.c @@ -0,0 +1,753 @@ +/* $Id: sd.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PURPOSE: Security descriptor functions + * FILE: lib/rtl/sd.c + * PROGRAMER: David Welch + * REVISION HISTORY: + * 26/07/98: Added stubs for security functions + */ + +/* INCLUDES *****************************************************************/ + +#include + +#include + +/* FUNCTIONS ***************************************************************/ + +NTSTATUS STDCALL +RtlCreateSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor, + ULONG Revision) +{ + if (Revision != 1) + { + return(STATUS_UNSUCCESSFUL); + } + + SecurityDescriptor->Revision = 1; + SecurityDescriptor->Sbz1 = 0; + SecurityDescriptor->Control = 0; + SecurityDescriptor->Owner = NULL; + SecurityDescriptor->Group = NULL; + SecurityDescriptor->Sacl = NULL; + SecurityDescriptor->Dacl = NULL; + + return(STATUS_SUCCESS); +} + +/* + * @implemented + */ +ULONG STDCALL +RtlLengthSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor) +{ + PSID Owner; + PSID Group; + ULONG Length; + PACL Dacl; + PACL Sacl; + + Length = sizeof(SECURITY_DESCRIPTOR); + + if (SecurityDescriptor->Owner != NULL) + { + Owner = SecurityDescriptor->Owner; + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + Owner = (PSID)((ULONG)Owner + + (ULONG)SecurityDescriptor); + } + Length = Length + ((sizeof(SID) + (Owner->SubAuthorityCount - 1) * + sizeof(ULONG) + 3) & 0xfc); + } + + if (SecurityDescriptor->Group != NULL) + { + Group = SecurityDescriptor->Group; + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + Group = (PSID)((ULONG)Group + (ULONG)SecurityDescriptor); + } + Length = Length + ((sizeof(SID) + (Group->SubAuthorityCount - 1) * + sizeof(ULONG) + 3) & 0xfc); + } + + if (SecurityDescriptor->Control & SE_DACL_PRESENT && + SecurityDescriptor->Dacl != NULL) + { + Dacl = SecurityDescriptor->Dacl; + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + Dacl = (PACL)((ULONG)Dacl + (PVOID)SecurityDescriptor); + } + Length = Length + ((Dacl->AclSize + 3) & 0xfc); + } + + if (SecurityDescriptor->Control & SE_SACL_PRESENT && + SecurityDescriptor->Sacl != NULL) + { + Sacl = SecurityDescriptor->Sacl; + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + Sacl = (PACL)((ULONG)Sacl + (PVOID)SecurityDescriptor); + } + Length = Length + ((Sacl->AclSize + 3) & 0xfc); + } + + return(Length); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlGetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor, + PBOOLEAN DaclPresent, + PACL* Dacl, + PBOOLEAN DaclDefaulted) +{ + if (SecurityDescriptor->Revision != 1) + { + return(STATUS_UNSUCCESSFUL); + } + if (!(SecurityDescriptor->Control & SE_DACL_PRESENT)) + { + *DaclPresent = 0; + return(STATUS_SUCCESS); + } + *DaclPresent = 1; + if (SecurityDescriptor->Dacl == NULL) + { + *Dacl = NULL; + } + else + { + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + *Dacl = (PACL)((ULONG)SecurityDescriptor->Dacl + + (PVOID)SecurityDescriptor); + } + else + { + *Dacl = SecurityDescriptor->Dacl; + } + } + if (SecurityDescriptor->Control & SE_DACL_DEFAULTED) + { + *DaclDefaulted = 1; + } + else + { + *DaclDefaulted = 0; + } + return(STATUS_SUCCESS); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor, + BOOLEAN DaclPresent, + PACL Dacl, + BOOLEAN DaclDefaulted) +{ + if (SecurityDescriptor->Revision != 1) + { + return(STATUS_UNSUCCESSFUL); + } + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + return(STATUS_UNSUCCESSFUL); + } + if (!DaclPresent) + { + SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_DACL_PRESENT); + return(STATUS_SUCCESS); + } + SecurityDescriptor->Control = SecurityDescriptor->Control | SE_DACL_PRESENT; + SecurityDescriptor->Dacl = Dacl; + SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_DACL_DEFAULTED); + if (DaclDefaulted) + { + SecurityDescriptor->Control = SecurityDescriptor->Control | SE_DACL_DEFAULTED; + } + return(STATUS_SUCCESS); +} + + +/* + * @implemented + */ +BOOLEAN STDCALL +RtlValidSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor) +{ + PSID Owner; + PSID Group; + PACL Sacl; + PACL Dacl; + + if (SecurityDescriptor->Revision != 1) + { + return(FALSE); + } + + Owner = SecurityDescriptor->Owner; + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + Owner = (PSID)((ULONG)Owner + (ULONG)SecurityDescriptor); + } + + if (!RtlValidSid(Owner)) + { + return(FALSE); + } + + Group = SecurityDescriptor->Group; + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + Group = (PSID)((ULONG)Group + (ULONG)SecurityDescriptor); + } + + if (!RtlValidSid(Group)) + { + return(FALSE); + } + + if (SecurityDescriptor->Control & SE_DACL_PRESENT && + SecurityDescriptor->Dacl != NULL) + { + Dacl = SecurityDescriptor->Dacl; + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + Dacl = (PACL)((ULONG)Dacl + (ULONG)SecurityDescriptor); + } + + if (!RtlValidAcl(Dacl)) + { + return(FALSE); + } + } + + if (SecurityDescriptor->Control & SE_SACL_PRESENT && + SecurityDescriptor->Sacl != NULL) + { + Sacl = SecurityDescriptor->Sacl; + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + Sacl = (PACL)((ULONG)Sacl + (ULONG)SecurityDescriptor); + } + + if (!RtlValidAcl(Sacl)) + { + return(FALSE); + } + } + + return(TRUE); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlSetOwnerSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor, + PSID Owner, + BOOLEAN OwnerDefaulted) +{ + if (SecurityDescriptor->Revision != 1) + { + return(STATUS_UNSUCCESSFUL); + } + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + return(STATUS_UNSUCCESSFUL); + } + SecurityDescriptor->Owner = Owner; + SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_OWNER_DEFAULTED); + if (OwnerDefaulted) + { + SecurityDescriptor->Control = SecurityDescriptor->Control | SE_OWNER_DEFAULTED; + } + return(STATUS_SUCCESS); +} + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlGetOwnerSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor, + PSID* Owner, + PBOOLEAN OwnerDefaulted) +{ + if (SecurityDescriptor->Revision != 1) + { + return(STATUS_UNSUCCESSFUL); + } + if (SecurityDescriptor->Owner != NULL) + { + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + *Owner = (PSID)((ULONG)SecurityDescriptor->Owner + + (PVOID)SecurityDescriptor); + } + else + { + *Owner = SecurityDescriptor->Owner; + } + } + else + { + *Owner = NULL; + } + if (SecurityDescriptor->Control & SE_OWNER_DEFAULTED) + { + *OwnerDefaulted = 1; + } + else + { + *OwnerDefaulted = 0; + } + return(STATUS_SUCCESS); +} + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlSetGroupSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor, + PSID Group, + BOOLEAN GroupDefaulted) +{ + if (SecurityDescriptor->Revision != 1) + { + return(STATUS_UNSUCCESSFUL); + } + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + return(STATUS_UNSUCCESSFUL); + } + SecurityDescriptor->Group = Group; + SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_GROUP_DEFAULTED); + if (GroupDefaulted) + { + SecurityDescriptor->Control = SecurityDescriptor->Control | SE_GROUP_DEFAULTED; + } + return(STATUS_SUCCESS); +} + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlGetGroupSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor, + PSID* Group, + PBOOLEAN GroupDefaulted) +{ + if (SecurityDescriptor->Revision != 1) + { + return(STATUS_UNSUCCESSFUL); + } + if (SecurityDescriptor->Group != NULL) + { + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + *Group = (PSID)((ULONG)SecurityDescriptor->Group + + (PVOID)SecurityDescriptor); + } + else + { + *Group = SecurityDescriptor->Group; + } + } + else + { + *Group = NULL; + } + if (SecurityDescriptor->Control & SE_GROUP_DEFAULTED) + { + *GroupDefaulted = 1; + } + else + { + *GroupDefaulted = 0; + } + return(STATUS_SUCCESS); +} + + +static VOID +RtlpQuerySecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor, + PSID* Owner, + PULONG OwnerLength, + PSID* Group, + PULONG GroupLength, + PACL* Dacl, + PULONG DaclLength, + PACL* Sacl, + PULONG SaclLength) +{ + if (SecurityDescriptor->Owner != NULL) + { + *Owner = SecurityDescriptor->Owner; + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + *Owner = (PSID)((ULONG)*Owner + (ULONG)SecurityDescriptor); + } + } + else + { + *Owner = NULL; + } + + if (*Owner != NULL) + { + *OwnerLength = (RtlLengthSid(*Owner) + 3) & ~3; + } + else + { + *OwnerLength = 0; + } + + if ((SecurityDescriptor->Control & SE_DACL_PRESENT) && + SecurityDescriptor->Dacl != NULL) + { + *Dacl = SecurityDescriptor->Dacl; + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + *Dacl = (PACL)((ULONG)*Dacl + (ULONG)SecurityDescriptor); + } + } + else + { + *Dacl = NULL; + } + + if (*Dacl != NULL) + { + *DaclLength = ((*Dacl)->AclSize + 3) & ~3; + } + else + { + *DaclLength = 0; + } + + if (SecurityDescriptor->Group != NULL) + { + *Group = SecurityDescriptor->Group; + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + *Group = (PSID)((ULONG)*Group + (ULONG)SecurityDescriptor); + } + } + else + { + *Group = NULL; + } + + if (*Group != NULL) + { + *GroupLength = (RtlLengthSid(*Group) + 3) & ~3; + } + else + { + *GroupLength = 0; + } + + if ((SecurityDescriptor->Control & SE_SACL_PRESENT) && + SecurityDescriptor->Sacl != NULL) + { + *Sacl = SecurityDescriptor->Sacl; + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + *Sacl = (PACL)((ULONG)*Sacl + (ULONG)SecurityDescriptor); + } + } + else + { + *Sacl = NULL; + } + + if (*Sacl != NULL) + { + *SaclLength = ((*Sacl)->AclSize + 3) & ~3; + } + else + { + *SaclLength = 0; + } +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlMakeSelfRelativeSD(PSECURITY_DESCRIPTOR AbsSD, + PSECURITY_DESCRIPTOR RelSD, + PULONG BufferLength) +{ + PSID Owner; + PSID Group; + PACL Sacl; + PACL Dacl; + ULONG OwnerLength; + ULONG GroupLength; + ULONG SaclLength; + ULONG DaclLength; + ULONG TotalLength; + ULONG Current; + + RtlpQuerySecurityDescriptor(AbsSD, + &Owner, + &OwnerLength, + &Group, + &GroupLength, + &Dacl, + &DaclLength, + &Sacl, + &SaclLength); + + TotalLength = OwnerLength + GroupLength + SaclLength + DaclLength + sizeof(SECURITY_DESCRIPTOR); + if (*BufferLength < TotalLength) + { + return(STATUS_BUFFER_TOO_SMALL); + } + + RtlZeroMemory(RelSD, + TotalLength); + memmove(RelSD, + AbsSD, + sizeof(SECURITY_DESCRIPTOR)); + Current = (ULONG)RelSD + sizeof(SECURITY_DESCRIPTOR); + + if (SaclLength != 0) + { + memmove((PVOID)Current, + Sacl, + SaclLength); + RelSD->Sacl = (PACL)((ULONG)Current - (ULONG)RelSD); + Current += SaclLength; + } + + if (DaclLength != 0) + { + memmove((PVOID)Current, + Dacl, + DaclLength); + RelSD->Dacl = (PACL)((ULONG)Current - (ULONG)RelSD); + Current += DaclLength; + } + + if (OwnerLength != 0) + { + memmove((PVOID)Current, + Owner, + OwnerLength); + RelSD->Owner = (PSID)((ULONG)Current - (ULONG)RelSD); + Current += OwnerLength; + } + + if (GroupLength != 0) + { + memmove((PVOID)Current, + Group, + GroupLength); + RelSD->Group = (PSID)((ULONG)Current - (ULONG)RelSD); + } + + RelSD->Control |= SE_SELF_RELATIVE; + + return(STATUS_SUCCESS); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlAbsoluteToSelfRelativeSD(PSECURITY_DESCRIPTOR AbsSD, + PSECURITY_DESCRIPTOR RelSD, + PULONG BufferLength + ) +{ + if (AbsSD->Control & SE_SELF_RELATIVE) + { + return(STATUS_BAD_DESCRIPTOR_FORMAT); + } + + return(RtlMakeSelfRelativeSD(AbsSD, RelSD, BufferLength)); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlGetControlSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor, + PSECURITY_DESCRIPTOR_CONTROL Control, + PULONG Revision) +{ + *Revision = SecurityDescriptor->Revision; + + if (SecurityDescriptor->Revision != 1) + { + return(STATUS_UNKNOWN_REVISION); + } + + *Control = SecurityDescriptor->Control; + + return(STATUS_SUCCESS); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlGetSaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor, + PBOOLEAN SaclPresent, + PACL *Sacl, + PBOOLEAN SaclDefaulted) +{ + if (SecurityDescriptor->Revision != 1) + { + return(STATUS_UNSUCCESSFUL); + } + if (!(SecurityDescriptor->Control & SE_SACL_PRESENT)) + { + *SaclPresent = 0; + return(STATUS_SUCCESS); + } + *SaclPresent = 1; + if (SecurityDescriptor->Sacl == NULL) + { + *Sacl = NULL; + } + else + { + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + *Sacl = (PACL)((ULONG)SecurityDescriptor->Sacl + + (PVOID)SecurityDescriptor); + } + else + { + *Sacl = SecurityDescriptor->Sacl; + } + } + if (SecurityDescriptor->Control & SE_SACL_DEFAULTED) + { + *SaclDefaulted = 1; + } + else + { + *SaclDefaulted = 0; + } + return(STATUS_SUCCESS); +} + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlSetSaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor, + BOOLEAN SaclPresent, + PACL Sacl, + BOOLEAN SaclDefaulted) +{ + if (SecurityDescriptor->Revision != 1) + { + return(STATUS_UNSUCCESSFUL); + } + if (SecurityDescriptor->Control & SE_SELF_RELATIVE) + { + return(STATUS_UNSUCCESSFUL); + } + if (!SaclPresent) + { + SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_SACL_PRESENT); + return(STATUS_SUCCESS); + } + SecurityDescriptor->Control = SecurityDescriptor->Control | SE_SACL_PRESENT; + SecurityDescriptor->Sacl = Sacl; + SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_SACL_DEFAULTED); + if (SaclDefaulted) + { + SecurityDescriptor->Control = SecurityDescriptor->Control | SE_SACL_DEFAULTED; + } + return(STATUS_SUCCESS); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlSelfRelativeToAbsoluteSD(PSECURITY_DESCRIPTOR RelSD, + PSECURITY_DESCRIPTOR AbsSD, + PDWORD AbsSDSize, + PACL Dacl, + PDWORD DaclSize, + PACL Sacl, + PDWORD SaclSize, + PSID Owner, + PDWORD OwnerSize, + PSID Group, + PDWORD GroupSize) +{ + ULONG OwnerLength; + ULONG GroupLength; + ULONG DaclLength; + ULONG SaclLength; + PSID pOwner; + PSID pGroup; + PACL pDacl; + PACL pSacl; + + if (!(RelSD->Control & SE_SELF_RELATIVE)) + return STATUS_BAD_DESCRIPTOR_FORMAT; + + RtlpQuerySecurityDescriptor (RelSD, + &pOwner, + &OwnerLength, + &pGroup, + &GroupLength, + &pDacl, + &DaclLength, + &pSacl, + &SaclLength); + + if (OwnerLength > *OwnerSize || + GroupLength > *GroupSize || + DaclLength > *DaclSize || + SaclLength > *SaclSize) + return STATUS_BUFFER_TOO_SMALL; + + memmove (Owner, pOwner, OwnerLength); + memmove (Group, pGroup, GroupLength); + memmove (Dacl, pDacl, DaclLength); + memmove (Sacl, pSacl, SaclLength); + + memmove (AbsSD, RelSD, sizeof (SECURITY_DESCRIPTOR)); + + AbsSD->Control &= ~SE_SELF_RELATIVE; + AbsSD->Owner = Owner; + AbsSD->Group = Group; + AbsSD->Dacl = Dacl; + AbsSD->Sacl = Sacl; + + *OwnerSize = OwnerLength; + *GroupSize = GroupLength; + *DaclSize = DaclLength; + *SaclSize = SaclLength; + + return STATUS_SUCCESS; +} + +/* EOF */ diff --git a/reactos/lib/rtl/security.c b/reactos/lib/rtl/security.c new file mode 100644 index 00000000000..c50ec28863d --- /dev/null +++ b/reactos/lib/rtl/security.c @@ -0,0 +1,150 @@ +/* $Id: security.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: lib/rtl/security.c + * PURPOSE: Miscellaneous securitiy related functions + * PROGRAMMER: Eric Kohl + * UPDATE HISTORY: + * 21/11/2001 Created + */ + +#include +#include + +#define NDEBUG +#include + + +/* FUNCTIONS ****************************************************************/ + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlImpersonateSelf(IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + SECURITY_QUALITY_OF_SERVICE SecQos; + HANDLE ProcessToken; + HANDLE ImpersonationToken; + NTSTATUS Status; + + Status = NtOpenProcessToken(NtCurrentProcess(), + TOKEN_DUPLICATE, + &ProcessToken); + if (!NT_SUCCESS(Status)) + return(Status); + + SecQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); + SecQos.ImpersonationLevel = ImpersonationLevel; + SecQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; + SecQos.EffectiveOnly = FALSE; + + ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES); + ObjectAttributes.RootDirectory = 0; + ObjectAttributes.ObjectName = NULL; + ObjectAttributes.Attributes = 0; + ObjectAttributes.SecurityDescriptor = NULL; + ObjectAttributes.SecurityQualityOfService = &SecQos; + + Status = NtDuplicateToken(ProcessToken, + TOKEN_IMPERSONATE, + &ObjectAttributes, + 0, + TokenImpersonation, + &ImpersonationToken); + if (!NT_SUCCESS(Status)) + { + NtClose(ProcessToken); + return(Status); + } + + Status = NtSetInformationThread(NtCurrentThread(), + ThreadImpersonationToken, + &ImpersonationToken, + sizeof(HANDLE)); + NtClose(ImpersonationToken); + NtClose(ProcessToken); + + return(Status); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlAdjustPrivilege(IN ULONG Privilege, + IN BOOLEAN Enable, + IN BOOLEAN CurrentThread, + OUT PBOOLEAN Enabled) +{ + TOKEN_PRIVILEGES NewState; + TOKEN_PRIVILEGES OldState; + ULONG ReturnLength; + HANDLE TokenHandle; + NTSTATUS Status; + + DPRINT ("RtlAdjustPrivilege() called\n"); + + if (CurrentThread) + { + Status = NtOpenThreadToken (NtCurrentThread (), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + FALSE, + &TokenHandle); + } + else + { + Status = NtOpenProcessToken (NtCurrentProcess (), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + &TokenHandle); + } + + if (!NT_SUCCESS (Status)) + { + DPRINT1 ("Retrieving token handle failed (Status %lx)\n", Status); + return Status; + } + + OldState.PrivilegeCount = 1; + + NewState.PrivilegeCount = 1; + NewState.Privileges[0].Luid.LowPart = Privilege; + NewState.Privileges[0].Luid.HighPart = 0; + NewState.Privileges[0].Attributes = (Enable) ? SE_PRIVILEGE_ENABLED : 0; + + Status = NtAdjustPrivilegesToken (TokenHandle, + FALSE, + &NewState, + sizeof(TOKEN_PRIVILEGES), + &OldState, + &ReturnLength); + NtClose (TokenHandle); + if (Status == STATUS_NOT_ALL_ASSIGNED) + { + DPRINT1 ("Failed to assign all privileges\n"); + return STATUS_PRIVILEGE_NOT_HELD; + } + if (!NT_SUCCESS(Status)) + { + DPRINT1 ("NtAdjustPrivilegesToken() failed (Status %lx)\n", Status); + return Status; + } + + if (OldState.PrivilegeCount == 0) + { + *Enabled = Enable; + } + else + { + *Enabled = (OldState.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED); + } + + DPRINT ("RtlAdjustPrivilege() done\n"); + + return STATUS_SUCCESS; +} + +/* EOF */ diff --git a/reactos/lib/rtl/sid.c b/reactos/lib/rtl/sid.c new file mode 100644 index 00000000000..10427eb302d --- /dev/null +++ b/reactos/lib/rtl/sid.c @@ -0,0 +1,353 @@ +/* $Id: sid.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PURPOSE: Security manager + * FILE: lib/rtl/sid.c + * PROGRAMER: David Welch + * REVISION HISTORY: + * 26/07/98: Added stubs for security functions + */ + +/* INCLUDES *****************************************************************/ + +#define __NTDRIVER__ +#include +#include + + +#define NDEBUG +#include + +/* FUNCTIONS ***************************************************************/ + +BOOLEAN STDCALL +RtlValidSid(IN PSID Sid) +{ + if ((Sid->Revision & 0xf) != 1) + { + return(FALSE); + } + if (Sid->SubAuthorityCount > 15) + { + return(FALSE); + } + return(TRUE); +} + + +/* + * @implemented + */ +ULONG STDCALL +RtlLengthRequiredSid(IN UCHAR SubAuthorityCount) +{ + return(sizeof(SID) + (SubAuthorityCount - 1) * sizeof(ULONG)); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlInitializeSid(IN PSID Sid, + IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority, + IN UCHAR SubAuthorityCount) +{ + Sid->Revision = 1; + Sid->SubAuthorityCount = SubAuthorityCount; + memcpy(&Sid->IdentifierAuthority, + IdentifierAuthority, + sizeof(SID_IDENTIFIER_AUTHORITY)); + return(STATUS_SUCCESS); +} + + +/* + * @implemented + */ +PULONG STDCALL +RtlSubAuthoritySid(IN PSID Sid, + IN ULONG SubAuthority) +{ + return(&Sid->SubAuthority[SubAuthority]); +} + + +/* + * @implemented + */ +PUCHAR STDCALL +RtlSubAuthorityCountSid(IN PSID Sid) +{ + return(&Sid->SubAuthorityCount); +} + + +/* + * @implemented + */ +BOOLEAN STDCALL +RtlEqualSid(IN PSID Sid1, + IN PSID Sid2) +{ + if (Sid1->Revision != Sid2->Revision) + { + return(FALSE); + } + if ((*RtlSubAuthorityCountSid(Sid1)) != (*RtlSubAuthorityCountSid(Sid2))) + { + return(FALSE); + } + if (RtlCompareMemory(Sid1, Sid2, RtlLengthSid(Sid1)) != 0) + { + return(FALSE); + } + return(TRUE); +} + + +/* + * @implemented + */ +ULONG STDCALL +RtlLengthSid(IN PSID Sid) +{ + return(sizeof(SID) + (Sid->SubAuthorityCount-1)*4); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlCopySid(ULONG BufferLength, + PSID Dest, + PSID Src) +{ + if (BufferLength < RtlLengthSid(Src)) + { + return(STATUS_UNSUCCESSFUL); + } + memmove(Dest, + Src, + RtlLengthSid(Src)); + return(STATUS_SUCCESS); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlCopySidAndAttributesArray(ULONG Count, + PSID_AND_ATTRIBUTES Src, + ULONG SidAreaSize, + PSID_AND_ATTRIBUTES Dest, + PVOID SidArea, + PVOID* RemainingSidArea, + PULONG RemainingSidAreaSize) +{ + ULONG SidLength; + ULONG Length; + ULONG i; + + Length = SidAreaSize; + + for (i=0; i Length) + { + return(STATUS_BUFFER_TOO_SMALL); + } + SidLength = RtlLengthSid(Src[i].Sid); + Length = Length - SidLength; + Dest[i].Sid = SidArea; + Dest[i].Attributes = Src[i].Attributes; + RtlCopySid(SidLength, + SidArea, + Src[i].Sid); + SidArea = SidArea + SidLength; + } + *RemainingSidArea = SidArea; + *RemainingSidAreaSize = Length; + return(STATUS_SUCCESS); +} + + +/* + * @implemented + */ +PSID_IDENTIFIER_AUTHORITY STDCALL +RtlIdentifierAuthoritySid(IN PSID Sid) +{ + return(&Sid->IdentifierAuthority); +} + + +/* + * @implemented + */ +NTSTATUS +STDCALL +RtlAllocateAndInitializeSid ( + PSID_IDENTIFIER_AUTHORITY IdentifierAuthority, + UCHAR SubAuthorityCount, + ULONG SubAuthority0, + ULONG SubAuthority1, + ULONG SubAuthority2, + ULONG SubAuthority3, + ULONG SubAuthority4, + ULONG SubAuthority5, + ULONG SubAuthority6, + ULONG SubAuthority7, + PSID *Sid +) +{ + PSID pSid; + + if (SubAuthorityCount > 8) + return STATUS_INVALID_SID; + + if (Sid == NULL) + return STATUS_INVALID_PARAMETER; + + pSid = (PSID)RtlAllocateHeap (RtlGetProcessHeap (), + 0, + SubAuthorityCount * sizeof(DWORD) + 8); + if (pSid == NULL) + return STATUS_NO_MEMORY; + + pSid->Revision = 1; + pSid->SubAuthorityCount = SubAuthorityCount; + memcpy (&pSid->IdentifierAuthority, + IdentifierAuthority, + sizeof(SID_IDENTIFIER_AUTHORITY)); + + switch (SubAuthorityCount) + { + case 8: + pSid->SubAuthority[7] = SubAuthority7; + case 7: + pSid->SubAuthority[6] = SubAuthority6; + case 6: + pSid->SubAuthority[5] = SubAuthority5; + case 5: + pSid->SubAuthority[4] = SubAuthority4; + case 4: + pSid->SubAuthority[3] = SubAuthority3; + case 3: + pSid->SubAuthority[2] = SubAuthority2; + case 2: + pSid->SubAuthority[1] = SubAuthority1; + case 1: + pSid->SubAuthority[0] = SubAuthority0; + break; + } + + *Sid = pSid; + + return STATUS_SUCCESS; +} + + +/* + * @implemented + */ +PSID STDCALL +RtlFreeSid(IN PSID Sid) +{ + RtlFreeHeap(RtlGetProcessHeap(), + 0, + Sid); + return(Sid); +} + + +/* + * @implemented + */ +BOOLEAN STDCALL +RtlEqualPrefixSid(IN PSID Sid1, + IN PSID Sid2) +{ + return(Sid1->SubAuthorityCount == Sid2->SubAuthorityCount && + !RtlCompareMemory(Sid1, Sid2, + (Sid1->SubAuthorityCount - 1) * sizeof(DWORD) + 8)); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlConvertSidToUnicodeString(PUNICODE_STRING String, + PSID Sid, + BOOLEAN AllocateBuffer) +{ + WCHAR Buffer[256]; + PWSTR wcs; + ULONG Length; + ULONG i; + + if (RtlValidSid (Sid) == FALSE) + return STATUS_INVALID_SID; + + wcs = Buffer; + wcs += swprintf (wcs, L"S-%u-", Sid->Revision); + if (Sid->IdentifierAuthority.Value[0] == 0 && + Sid->IdentifierAuthority.Value[1] == 0) + { + wcs += swprintf (wcs, + L"%lu", + (ULONG)Sid->IdentifierAuthority.Value[2] << 24 | + (ULONG)Sid->IdentifierAuthority.Value[3] << 16 | + (ULONG)Sid->IdentifierAuthority.Value[4] << 8 | + (ULONG)Sid->IdentifierAuthority.Value[5]); + } + else + { + wcs += swprintf (wcs, + L"0x%02hx%02hx%02hx%02hx%02hx%02hx", + Sid->IdentifierAuthority.Value[0], + Sid->IdentifierAuthority.Value[1], + Sid->IdentifierAuthority.Value[2], + Sid->IdentifierAuthority.Value[3], + Sid->IdentifierAuthority.Value[4], + Sid->IdentifierAuthority.Value[5]); + } + + for (i = 0; i < Sid->SubAuthorityCount; i++) + { + wcs += swprintf (wcs, + L"-%u", + Sid->SubAuthority[i]); + } + + Length = (wcs - Buffer) * sizeof(WCHAR); + if (AllocateBuffer) + { + String->Buffer = RtlAllocateHeap (RtlGetProcessHeap (), + 0, + Length + sizeof(WCHAR)); + if (String->Buffer == NULL) + return STATUS_NO_MEMORY; + String->MaximumLength = Length + sizeof(WCHAR); + } + else + { + if (Length > String->MaximumLength) + return STATUS_BUFFER_TOO_SMALL; + } + + String->Length = Length; + RtlCopyMemory (String->Buffer, + Buffer, + Length); + if (Length < String->MaximumLength) + String->Buffer[Length / sizeof(WCHAR)] = 0; + + return STATUS_SUCCESS; +} + +/* EOF */ diff --git a/reactos/lib/rtl/time.c b/reactos/lib/rtl/time.c new file mode 100644 index 00000000000..cc22ee5b230 --- /dev/null +++ b/reactos/lib/rtl/time.c @@ -0,0 +1,412 @@ +/* $Id: time.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: lib/rtl/time.c + * PURPOSE: Conversion between Time and TimeFields + * PROGRAMMER: Rex Jolliff (rex@lvcablemodem.com) + * UPDATE HISTORY: + * Created 22/05/98 + * 08/03/98 RJJ Implemented these functions + */ + +/* INCLUDES *****************************************************************/ + +#include +#include + +#define NDEBUG +#include + +#define TICKSPERMIN 600000000 +#define TICKSPERSEC 10000000 +#define TICKSPERMSEC 10000 +#define SECSPERDAY 86400 +#define SECSPERHOUR 3600 +#define SECSPERMIN 60 +#define MINSPERHOUR 60 +#define HOURSPERDAY 24 +#define EPOCHWEEKDAY 1 +#define DAYSPERWEEK 7 +#define EPOCHYEAR 1601 +#define DAYSPERNORMALYEAR 365 +#define DAYSPERLEAPYEAR 366 +#define MONSPERYEAR 12 + +#if defined(__GNUC__) +#define TICKSTO1970 0x019db1ded53e8000LL +#define TICKSTO1980 0x01a8e79fe1d58000LL +#else +#define TICKSTO1970 0x019db1ded53e8000i64 +#define TICKSTO1980 0x01a8e79fe1d58000i64 +#endif + + +static const int YearLengths[2] = + { + DAYSPERNORMALYEAR, DAYSPERLEAPYEAR + }; +static const int MonthLengths[2][MONSPERYEAR] = + { + { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } + }; + +static __inline int IsLeapYear(int Year) +{ + return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0; +} + +static __inline void NormalizeTimeFields(CSHORT *FieldToNormalize, + CSHORT *CarryField, + int Modulus) +{ + *FieldToNormalize = (CSHORT) (*FieldToNormalize - Modulus); + *CarryField = (CSHORT) (*CarryField + 1); +} + +/* FUNCTIONS *****************************************************************/ + +/* + * @implemented + */ +BOOLEAN +STDCALL +RtlTimeFieldsToTime( + PTIME_FIELDS tfTimeFields, + PLARGE_INTEGER Time) +{ + int CurYear; + int CurMonth; +#if defined(__GNUC__) + + long long int rcTime; +#else + + __int64 rcTime; +#endif + + TIME_FIELDS TimeFields = *tfTimeFields; + + rcTime = 0; + + /* FIXME: normalize the TIME_FIELDS structure here */ + while (TimeFields.Second >= SECSPERMIN) + { + NormalizeTimeFields(&TimeFields.Second, + &TimeFields.Minute, + SECSPERMIN); + } + while (TimeFields.Minute >= MINSPERHOUR) + { + NormalizeTimeFields(&TimeFields.Minute, + &TimeFields.Hour, + MINSPERHOUR); + } + while (TimeFields.Hour >= HOURSPERDAY) + { + NormalizeTimeFields(&TimeFields.Hour, + &TimeFields.Day, + HOURSPERDAY); + } + while (TimeFields.Day > + MonthLengths[IsLeapYear(TimeFields.Year)][TimeFields.Month - 1]) + { + NormalizeTimeFields(&TimeFields.Day, + &TimeFields.Month, + SECSPERMIN); + } + while (TimeFields.Month > MONSPERYEAR) + { + NormalizeTimeFields(&TimeFields.Month, + &TimeFields.Year, + MONSPERYEAR); + } + + /* FIXME: handle calendar corrections here */ + for (CurYear = EPOCHYEAR; CurYear < TimeFields.Year; CurYear++) + { + rcTime += YearLengths[IsLeapYear(CurYear)]; + } + for (CurMonth = 1; CurMonth < TimeFields.Month; CurMonth++) + { + rcTime += MonthLengths[IsLeapYear(CurYear)][CurMonth - 1]; + } + rcTime += TimeFields.Day - 1; + rcTime *= SECSPERDAY; + rcTime += TimeFields.Hour * SECSPERHOUR + TimeFields.Minute * SECSPERMIN + + TimeFields.Second; + rcTime *= TICKSPERSEC; + rcTime += TimeFields.Milliseconds * TICKSPERMSEC; + *Time = *(LARGE_INTEGER *)&rcTime; + + return TRUE; +} + + + +/* + * @implemented + */ +VOID +STDCALL +RtlTimeToElapsedTimeFields(IN PLARGE_INTEGER Time, + OUT PTIME_FIELDS TimeFields) +{ + ULONGLONG ElapsedSeconds; + ULONG SecondsInDay; + ULONG SecondsInMinute; + + /* Extract millisecond from time */ + TimeFields->Milliseconds = (CSHORT)((Time->QuadPart % TICKSPERSEC) / TICKSPERMSEC); + + /* Compute elapsed seconds */ + ElapsedSeconds = (ULONGLONG)Time->QuadPart / TICKSPERSEC; + + /* Compute seconds within the day */ + SecondsInDay = ElapsedSeconds % SECSPERDAY; + + /* Compute elapsed minutes within the day */ + SecondsInMinute = SecondsInDay % SECSPERHOUR; + + /* Compute elapsed time of day */ + TimeFields->Hour = (CSHORT)(SecondsInDay / SECSPERHOUR); + TimeFields->Minute = (CSHORT)(SecondsInMinute / SECSPERMIN); + TimeFields->Second = (CSHORT)(SecondsInMinute % SECSPERMIN); + + /* Compute elapsed days */ + TimeFields->Day = (CSHORT)(ElapsedSeconds / SECSPERDAY); + + /* The elapsed number of months and days cannot be calculated */ + TimeFields->Month = 0; + TimeFields->Year = 0; +} + + + +/* + * @unimplemented + */ +VOID +STDCALL +RtlTimeToTimeFields( + PLARGE_INTEGER liTime, + PTIME_FIELDS TimeFields) +{ + const int *Months; + int LeapSecondCorrections, SecondsInDay, CurYear; + int LeapYear, CurMonth, GMTOffset; + long int Days; +#if defined(__GNUC__) + + long long int Time = (long long int)liTime->QuadPart; +#else + + __int64 Time = (__int64)liTime->QuadPart; +#endif + + /* Extract millisecond from time and convert time into seconds */ + TimeFields->Milliseconds = (CSHORT) ((Time % TICKSPERSEC) / TICKSPERMSEC); + Time = Time / TICKSPERSEC; + + /* FIXME: Compute the number of leap second corrections here */ + LeapSecondCorrections = 0; + + /* FIXME: get the GMT offset here */ + GMTOffset = 0; + + /* Split the time into days and seconds within the day */ + Days = Time / SECSPERDAY; + SecondsInDay = Time % SECSPERDAY; + + /* Adjust the values for GMT and leap seconds */ + SecondsInDay += (GMTOffset - LeapSecondCorrections); + while (SecondsInDay < 0) + { + SecondsInDay += SECSPERDAY; + Days--; + } + while (SecondsInDay >= SECSPERDAY) + { + SecondsInDay -= SECSPERDAY; + Days++; + } + + /* compute time of day */ + TimeFields->Hour = (CSHORT) (SecondsInDay / SECSPERHOUR); + SecondsInDay = SecondsInDay % SECSPERHOUR; + TimeFields->Minute = (CSHORT) (SecondsInDay / SECSPERMIN); + TimeFields->Second = (CSHORT) (SecondsInDay % SECSPERMIN); + + /* FIXME: handle the possibility that we are on a leap second (i.e. Second = 60) */ + + /* compute day of week */ + TimeFields->Weekday = (CSHORT) ((EPOCHWEEKDAY + Days) % DAYSPERWEEK); + + /* compute year */ + CurYear = EPOCHYEAR; + CurYear += Days / DAYSPERLEAPYEAR; + Days -= (CurYear - EPOCHYEAR) * DAYSPERLEAPYEAR; + CurYear--; /* The next calculation needs CurYear - 1 */ + Days += CurYear - CurYear / 4 + CurYear / 100 - CurYear / 400; + CurYear++; + Days -= EPOCHYEAR - 1 - (EPOCHYEAR -1) / 4 + (EPOCHYEAR -1) / 100 - (EPOCHYEAR - 1) / 400; + /* FIXME: handle calendar modifications */ + while (1) + { + LeapYear = IsLeapYear(CurYear); + if (Days < (long) YearLengths[LeapYear]) + { + break; + } + CurYear++; + Days = Days - (long) YearLengths[LeapYear]; + } + TimeFields->Year = (CSHORT) CurYear; + + /* Compute month of year */ + LeapYear = IsLeapYear(CurYear); + Months = MonthLengths[LeapYear]; + for (CurMonth = 0; Days >= (long) Months[CurMonth]; CurMonth++) + Days = Days - (long) Months[CurMonth]; + TimeFields->Month = (CSHORT) (CurMonth + 1); + TimeFields->Day = (CSHORT) (Days + 1); +} + + +/* + * @implemented + */ +BOOLEAN +STDCALL +RtlTimeToSecondsSince1970( + PLARGE_INTEGER Time, + PULONG SecondsSince1970) +{ + LARGE_INTEGER liTime; + + liTime.QuadPart = Time->QuadPart - TICKSTO1970; + liTime.QuadPart = liTime.QuadPart / TICKSPERSEC; + + if (liTime.u.HighPart != 0) + return FALSE; + + *SecondsSince1970 = liTime.u.LowPart; + + return TRUE; +} + + +/* + * @implemented + */ +BOOLEAN +STDCALL +RtlTimeToSecondsSince1980( + PLARGE_INTEGER Time, + PULONG SecondsSince1980) +{ + LARGE_INTEGER liTime; + + liTime.QuadPart = Time->QuadPart - TICKSTO1980; + liTime.QuadPart = liTime.QuadPart / TICKSPERSEC; + + if (liTime.u.HighPart != 0) + return FALSE; + + *SecondsSince1980 = liTime.u.LowPart; + + return TRUE; +} + + +/* + * @implemented + */ +NTSTATUS +STDCALL +RtlLocalTimeToSystemTime(PLARGE_INTEGER LocalTime, + PLARGE_INTEGER SystemTime) +{ + SYSTEM_TIMEOFDAY_INFORMATION TimeInformation; + NTSTATUS Status; + + Status = NtQuerySystemInformation(SystemTimeOfDayInformation, + &TimeInformation, + sizeof(SYSTEM_TIMEOFDAY_INFORMATION), + NULL); + if (!NT_SUCCESS(Status)) + return(Status); + + SystemTime->QuadPart = LocalTime->QuadPart + + TimeInformation.TimeZoneBias.QuadPart; + + return(STATUS_SUCCESS); +} + + + + +/* + * @implemented + */ +NTSTATUS +STDCALL +RtlSystemTimeToLocalTime(PLARGE_INTEGER SystemTime, + PLARGE_INTEGER LocalTime) +{ + SYSTEM_TIMEOFDAY_INFORMATION TimeInformation; + NTSTATUS Status; + + Status = NtQuerySystemInformation(SystemTimeOfDayInformation, + &TimeInformation, + sizeof(SYSTEM_TIMEOFDAY_INFORMATION), + NULL); + if (!NT_SUCCESS(Status)) + return(Status); + + LocalTime->QuadPart = SystemTime->QuadPart - + TimeInformation.TimeZoneBias.QuadPart; + + return(STATUS_SUCCESS); +} + + +/* + * @implemented + */ +VOID +STDCALL +RtlSecondsSince1970ToTime( + ULONG SecondsSince1970, + PLARGE_INTEGER Time) +{ + LONGLONG llTime; + + llTime = (SecondsSince1970 * TICKSPERSEC) + TICKSTO1970; + + *Time = *(LARGE_INTEGER *)&llTime; +} + + +/* + * @implemented + */ +VOID +STDCALL +RtlSecondsSince1980ToTime( + ULONG SecondsSince1980, + PLARGE_INTEGER Time) +{ + LONGLONG llTime; + + llTime = (SecondsSince1980 * TICKSPERSEC) + TICKSTO1980; + + *Time = *(LARGE_INTEGER *)&llTime; +} + + + +/* EOF */ diff --git a/reactos/lib/rtl/timezone.c b/reactos/lib/rtl/timezone.c new file mode 100644 index 00000000000..b65c47d65a0 --- /dev/null +++ b/reactos/lib/rtl/timezone.c @@ -0,0 +1,175 @@ +/* $Id: timezone.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PURPOSE: Timezone functions + * FILE: lib/rtl/timezone.c + * PROGRAMER: Eric Kohl + * REVISION HISTORY: + * 29/05/2001: Created + */ + +/* INCLUDES *****************************************************************/ + +#include +#include +#include + +#define NDEBUG +#include + + +/* FUNCTIONS *****************************************************************/ + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlQueryTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation) +{ + RTL_QUERY_REGISTRY_TABLE QueryTable[8]; + UNICODE_STRING StandardName; + UNICODE_STRING DaylightName; + NTSTATUS Status; + + DPRINT("RtlQueryTimeZoneInformation()\n"); + + RtlZeroMemory(QueryTable, + sizeof(QueryTable)); + + StandardName.Length = 0; + StandardName.MaximumLength = 32 * sizeof(WCHAR); + StandardName.Buffer = TimeZoneInformation->StandardName; + + DaylightName.Length = 0; + DaylightName.MaximumLength = 32 * sizeof(WCHAR); + DaylightName.Buffer = TimeZoneInformation->DaylightName; + + QueryTable[0].Name = L"Bias"; + QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + QueryTable[0].EntryContext = &TimeZoneInformation->Bias; + + QueryTable[1].Name = L"Standard Name"; + QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; + QueryTable[1].EntryContext = &StandardName; + + QueryTable[2].Name = L"Standard Bias"; + QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT; + QueryTable[2].EntryContext = &TimeZoneInformation->StandardBias; + + QueryTable[3].Name = L"Standard Start"; + QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT; + QueryTable[3].EntryContext = &TimeZoneInformation->StandardDate; + + QueryTable[4].Name = L"Daylight Name"; + QueryTable[4].Flags = RTL_QUERY_REGISTRY_DIRECT; + QueryTable[4].EntryContext = &DaylightName; + + QueryTable[5].Name = L"Daylight Bias"; + QueryTable[5].Flags = RTL_QUERY_REGISTRY_DIRECT; + QueryTable[5].EntryContext = &TimeZoneInformation->DaylightBias; + + QueryTable[6].Name = L"Daylight Start"; + QueryTable[6].Flags = RTL_QUERY_REGISTRY_DIRECT; + QueryTable[6].EntryContext = &TimeZoneInformation->DaylightDate; + + Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, + L"TimeZoneInformation", + QueryTable, + NULL, + NULL); + + return Status; +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation) +{ + ULONG Length; + NTSTATUS Status; + + DPRINT("RtlSetTimeZoneInformation()\n"); + + Status = RtlWriteRegistryValue(RTL_REGISTRY_CONTROL, + L"TimeZoneInformation", + L"Bias", + REG_DWORD, + &TimeZoneInformation->Bias, + sizeof(LONG)); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Length = (wcslen(TimeZoneInformation->StandardName) + 1) * sizeof(WCHAR); + Status = RtlWriteRegistryValue(RTL_REGISTRY_CONTROL, + L"TimeZoneInformation", + L"Standard Name", + REG_SZ, + TimeZoneInformation->StandardName, + Length); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Status = RtlWriteRegistryValue(RTL_REGISTRY_CONTROL, + L"TimeZoneInformation", + L"Standard Bias", + REG_DWORD, + &TimeZoneInformation->StandardBias, + sizeof(LONG)); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Status = RtlWriteRegistryValue(RTL_REGISTRY_CONTROL, + L"TimeZoneInformation", + L"Standard Start", + REG_BINARY, + &TimeZoneInformation->StandardDate, + sizeof(SYSTEMTIME)); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Length = (wcslen(TimeZoneInformation->DaylightName) + 1) * sizeof(WCHAR); + Status = RtlWriteRegistryValue(RTL_REGISTRY_CONTROL, + L"TimeZoneInformation", + L"Daylight Name", + REG_SZ, + TimeZoneInformation->DaylightName, + Length); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Status = RtlWriteRegistryValue(RTL_REGISTRY_CONTROL, + L"TimeZoneInformation", + L"Daylight Bias", + REG_DWORD, + &TimeZoneInformation->DaylightBias, + sizeof(LONG)); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Status = RtlWriteRegistryValue(RTL_REGISTRY_CONTROL, + L"TimeZoneInformation", + L"Daylight Start", + REG_BINARY, + &TimeZoneInformation->DaylightDate, + sizeof(SYSTEMTIME)); + + return Status; +} + +/* EOF */ diff --git a/reactos/lib/rtl/unicode.c b/reactos/lib/rtl/unicode.c new file mode 100644 index 00000000000..83ee674408c --- /dev/null +++ b/reactos/lib/rtl/unicode.c @@ -0,0 +1,2498 @@ +/* + * Rtl string functions + * + * Copyright (C) 1996-1998 Marcus Meissner + * Copyright (C) 2000 Alexandre Julliard + * Copyright (C) 2003 Thomas Mertes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#define __NTDRIVER__ +#include + +#include + +#include +#include + +#define NDEBUG +#include + +/* GLOBALS *******************************************************************/ + +#define TAG_USTR TAG('U', 'S', 'T', 'R') +#define TAG_ASTR TAG('A', 'S', 'T', 'R') +#define TAG_OSTR TAG('O', 'S', 'T', 'R') + + +extern BOOLEAN NlsMbCodePageTag; +extern BOOLEAN NlsMbOemCodePageTag; + +/* FUNCTIONS *****************************************************************/ + + + +WCHAR STDCALL +RtlAnsiCharToUnicodeChar (IN CHAR AnsiChar) +{ + ULONG Size; + WCHAR UnicodeChar; + + Size = 1; +#if 0 + + Size = (NlsLeadByteInfo[AnsiChar] == 0) ? 1 : 2; +#endif + + RtlMultiByteToUnicodeN (&UnicodeChar, + sizeof(WCHAR), + NULL, + &AnsiChar, + Size); + + return UnicodeChar; +} + + +/* + * @implemented + * + * RETURNS + * The calculated size in bytes including nullterm. + */ +ULONG +STDCALL +RtlAnsiStringToUnicodeSize(IN PANSI_STRING AnsiString) +{ + ULONG Size; + + RtlMultiByteToUnicodeSize(&Size, + AnsiString->Buffer, + AnsiString->Length); + + return(Size); +} + + + +/* + * @implemented + * + * NOTES + * If src->length is zero dest is unchanged. + * Dest is never nullterminated. + */ +NTSTATUS +STDCALL +RtlAppendStringToString(IN OUT PSTRING Destination, + IN PSTRING Source) +{ + PCHAR Ptr; + + if (Source->Length == 0) + return(STATUS_SUCCESS); + + if (Destination->Length + Source->Length >= Destination->MaximumLength) + return(STATUS_BUFFER_TOO_SMALL); + + Ptr = Destination->Buffer + Destination->Length; + memmove(Ptr, + Source->Buffer, + Source->Length); + Ptr += Source->Length; + *Ptr = 0; + + Destination->Length += Source->Length; + + return(STATUS_SUCCESS); +} + + + +/* + * @implemented + * + * NOTES + * If src->length is zero dest is unchanged. + * Dest is nullterminated when the MaximumLength allowes it. + * When dest fits exactly in MaximumLength characters the nullterm is ommitted. + */ +NTSTATUS +STDCALL +RtlAppendUnicodeStringToString( + IN OUT PUNICODE_STRING Destination, + IN PUNICODE_STRING Source) +{ + + if ((Source->Length + Destination->Length) > Destination->MaximumLength) + return STATUS_BUFFER_TOO_SMALL; + + memcpy((char*)Destination->Buffer + Destination->Length, Source->Buffer, Source->Length); + Destination->Length += Source->Length; + /* append terminating '\0' if enough space */ + if( Destination->MaximumLength > Destination->Length ) + Destination->Buffer[Destination->Length / sizeof(WCHAR)] = 0; + + return STATUS_SUCCESS; +} + + +/* + * @implemented + */ +NTSTATUS +STDCALL +RtlCharToInteger( + IN PCSZ String, + IN ULONG Base, + IN OUT PULONG Value) +{ + ULONG Val; + + *Value = 0; + + if (Base == 0) + { + Base = 10; + if (*String == '0') + { + Base = 8; + String++; + if ((*String == 'x') && isxdigit (String[1])) + { + String++; + Base = 16; + } + } + } + + if (!isxdigit (*String)) + return STATUS_INVALID_PARAMETER; + + while (isxdigit (*String) && + (Val = isdigit (*String) ? * String - '0' : (islower (*String) + ? toupper (*String) : *String) - 'A' + 10) < Base) + { + *Value = *Value * Base + Val; + String++; + } + + return STATUS_SUCCESS; +} + + + +/* + * @implemented + */ +LONG +STDCALL +RtlCompareString( + IN PSTRING String1, + IN PSTRING String2, + IN BOOLEAN CaseInsensitive) +{ + ULONG len1, len2; + PCHAR s1, s2; + CHAR c1, c2; + + if (String1 && String2) + { + len1 = String1->Length; + len2 = String2->Length; + s1 = String1->Buffer; + s2 = String2->Buffer; + + if (s1 && s2) + { + if (CaseInsensitive) + { + while (1) + { + c1 = len1-- ? RtlUpperChar (*s1++) : 0; + c2 = len2-- ? RtlUpperChar (*s2++) : 0; + if (!c1 || !c2 || c1 != c2) + return c1 - c2; + } + } + else + { + while (1) + { + c1 = len1-- ? *s1++ : 0; + c2 = len2-- ? *s2++ : 0; + if (!c1 || !c2 || c1 != c2) + return c1 - c2; + } + } + } + } + + return 0; +} + + +/* + * @implemented + * + * RETURNS + * TRUE if strings are equal. + */ +BOOLEAN +STDCALL +RtlEqualString( + IN PSTRING String1, + IN PSTRING String2, + IN BOOLEAN CaseInsensitive) +{ + ULONG i; + CHAR c1, c2; + PCHAR p1, p2; + + if (String1->Length != String2->Length) + return FALSE; + + p1 = String1->Buffer; + p2 = String2->Buffer; + for (i = 0; i < String1->Length; i++) + { + if (CaseInsensitive == TRUE) + { + c1 = RtlUpperChar (*p1); + c2 = RtlUpperChar (*p2); + } + else + { + c1 = *p1; + c2 = *p2; + } + + if (c1 != c2) + return FALSE; + + p1++; + p2++; + } + + return TRUE; +} + + +/* + * @implemented + * + * RETURNS + * TRUE if strings are equal. + */ +BOOLEAN +STDCALL +RtlEqualUnicodeString( + IN PUNICODE_STRING String1, + IN PUNICODE_STRING String2, + IN BOOLEAN CaseInsensitive) +{ + ULONG i; + WCHAR wc1, wc2; + PWCHAR pw1, pw2; + + if (String1->Length != String2->Length) + return FALSE; + + pw1 = String1->Buffer; + pw2 = String2->Buffer; + + for (i = 0; i < String1->Length / sizeof(WCHAR); i++) + { + if (CaseInsensitive == TRUE) + { + wc1 = RtlUpcaseUnicodeChar (*pw1); + wc2 = RtlUpcaseUnicodeChar (*pw2); + } + else + { + wc1 = *pw1; + wc2 = *pw2; + } + + if (wc1 != wc2) + return FALSE; + + pw1++; + pw2++; + } + + return TRUE; +} + + +/* + * @implemented + */ +VOID +STDCALL +RtlFreeAnsiString(IN PANSI_STRING AnsiString) +{ + if (AnsiString->Buffer == NULL) + return; + + ExFreePool(AnsiString->Buffer); + + AnsiString->Buffer = NULL; + AnsiString->Length = 0; + AnsiString->MaximumLength = 0; +} + + +/* + * @implemented + */ +VOID +STDCALL +RtlFreeOemString(IN POEM_STRING OemString) +{ + if (OemString->Buffer == NULL) + return; + + ExFreePool(OemString->Buffer); + + OemString->Buffer = NULL; + OemString->Length = 0; + OemString->MaximumLength = 0; +} + + +/* + * @implemented + */ +VOID +STDCALL +RtlFreeUnicodeString(IN PUNICODE_STRING UnicodeString) +{ + if (UnicodeString->Buffer == NULL) + return; + + ExFreePool(UnicodeString->Buffer); + + UnicodeString->Buffer = NULL; + UnicodeString->Length = 0; + UnicodeString->MaximumLength = 0; +} + + +/* + * @implemented + * + * NOTES + * If source is NULL the length of source is assumed to be 0. + */ +VOID +STDCALL +RtlInitAnsiString(IN OUT PANSI_STRING DestinationString, + IN PCSZ SourceString) +{ + ULONG DestSize; + + if (SourceString == NULL) + { + DestinationString->Length = 0; + DestinationString->MaximumLength = 0; + } + else + { + DestSize = strlen ((const char *)SourceString); + DestinationString->Length = DestSize; + DestinationString->MaximumLength = DestSize + sizeof(CHAR); + } + DestinationString->Buffer = (PCHAR)SourceString; +} + + + +/* + * @implemented + * + * NOTES + * If source is NULL the length of source is assumed to be 0. + */ +VOID +STDCALL +RtlInitString( + IN OUT PSTRING DestinationString, + IN PCSZ SourceString) +{ + ULONG DestSize; + + if (SourceString == NULL) + { + DestinationString->Length = 0; + DestinationString->MaximumLength = 0; + } + else + { + DestSize = strlen((const char *)SourceString); + DestinationString->Length = DestSize; + DestinationString->MaximumLength = DestSize + sizeof(CHAR); + } + DestinationString->Buffer = (PCHAR)SourceString; +} + + +/* + * @implemented + * + * NOTES + * If source is NULL the length of source is assumed to be 0. + */ +VOID +STDCALL +RtlInitUnicodeString(IN OUT PUNICODE_STRING DestinationString, + IN PCWSTR SourceString) +{ + ULONG DestSize; + + DPRINT("RtlInitUnicodeString(DestinationString %x, SourceString %x)\n", + DestinationString, + SourceString); + + if (SourceString == NULL) + { + DestinationString->Length = 0; + DestinationString->MaximumLength = 0; + } + else + { + DestSize = wcslen((PWSTR)SourceString) * sizeof(WCHAR); + DestinationString->Length = DestSize; + DestinationString->MaximumLength = DestSize + sizeof(WCHAR); + } + DestinationString->Buffer = (PWSTR)SourceString; +} + + + +/* + * @implemented + * + * NOTES + * Writes at most length characters to the string str. + * Str is nullterminated when length allowes it. + * When str fits exactly in length characters the nullterm is ommitted. + */ +NTSTATUS +STDCALL +RtlIntegerToChar( + IN ULONG Value, + IN ULONG Base, + IN ULONG Length, + IN OUT PCHAR String) +{ + ULONG Radix; + CHAR temp[33]; + ULONG v = Value; + ULONG i; + PCHAR tp; + PCHAR sp; + + Radix = Base; + if (Radix == 0) + Radix = 10; + + if ((Radix != 2) && (Radix != 8) && + (Radix != 10) && (Radix != 16)) + return STATUS_INVALID_PARAMETER; + + tp = temp; + while (v || tp == temp) + { + i = v % Radix; + v = v / Radix; + if (i < 10) + *tp = i + '0'; + else + *tp = i + 'a' - 10; + tp++; + } + + if (tp - temp >= Length) + return STATUS_BUFFER_TOO_SMALL; + + sp = String; + while (tp > temp) + *sp++ = *--tp; + *sp = 0; + + return STATUS_SUCCESS; +} + + + +/* + * @implemented + */ +NTSTATUS +STDCALL +RtlIntegerToUnicodeString( + IN ULONG Value, + IN ULONG Base, /* optional */ + IN OUT PUNICODE_STRING String) +{ + ANSI_STRING AnsiString; + CHAR Buffer[33]; + NTSTATUS Status; + + Status = RtlIntegerToChar (Value, + Base, + 33, + Buffer); + if (!NT_SUCCESS(Status)) + return Status; + + AnsiString.Buffer = Buffer; + AnsiString.Length = strlen (Buffer); + AnsiString.MaximumLength = 33; + + Status = RtlAnsiStringToUnicodeString (String, + &AnsiString, + FALSE); + + return Status; +} + + +/* + * @implemented + * + * RETURNS + * TRUE if String2 contains String1 as a prefix. + */ +BOOLEAN +STDCALL +RtlPrefixString( + PANSI_STRING String1, + PANSI_STRING String2, + BOOLEAN CaseInsensitive) +{ + PCHAR pc1; + PCHAR pc2; + ULONG Length; + + if (String2->Length < String1->Length) + return FALSE; + + Length = String1->Length; + pc1 = String1->Buffer; + pc2 = String2->Buffer; + + if (pc1 && pc2) + { + if (CaseInsensitive) + { + while (Length--) + { + if (RtlUpperChar (*pc1++) != RtlUpperChar (*pc2++)) + return FALSE; + } + } + else + { + while (Length--) + { + if (*pc1++ != *pc2++) + return FALSE; + } + } + return TRUE; + } + return FALSE; +} + + +/* + * @implemented + * + * RETURNS + * TRUE if String2 contains String1 as a prefix. + */ +BOOLEAN +STDCALL +RtlPrefixUnicodeString( + PUNICODE_STRING String1, + PUNICODE_STRING String2, + BOOLEAN CaseInsensitive) +{ + PWCHAR pc1; + PWCHAR pc2; + ULONG Length; + + if (String2->Length < String1->Length) + return FALSE; + + Length = String1->Length / 2; + pc1 = String1->Buffer; + pc2 = String2->Buffer; + + if (pc1 && pc2) + { + if (CaseInsensitive) + { + while (Length--) + { + if (RtlUpcaseUnicodeChar (*pc1++) + != RtlUpcaseUnicodeChar (*pc2++)) + return FALSE; + } + } + else + { + while (Length--) + { + if( *pc1++ != *pc2++ ) + return FALSE; + } + } + return TRUE; + } + return FALSE; +} + + + +/* + * @implemented + */ +NTSTATUS +STDCALL +RtlUnicodeStringToInteger( + IN PUNICODE_STRING String, + IN ULONG Base, + OUT PULONG Value) +{ + PWCHAR Str; + ULONG lenmin = 0; + ULONG i; + ULONG Val; + BOOLEAN addneg = FALSE; + + *Value = 0; + Str = String->Buffer; + + for (i = 0; i < String->Length / sizeof(WCHAR); i++) + { + if (*Str == L'b') + { + Base = 2; + lenmin++; + } + else if (*Str == L'o') + { + Base = 8; + lenmin++; + } + else if (*Str == L'd') + { + Base = 10; + lenmin++; + } + else if (*Str == L'x') + { + Base = 16; + lenmin++; + } + else if (*Str == L'+') + { + lenmin++; + } + else if (*Str == L'-') + { + addneg = TRUE; + lenmin++; + } + else if ((*Str > L'1') && (Base == 2)) + { + return STATUS_INVALID_PARAMETER; + } + else if (((*Str > L'7') || (*Str < L'0')) && (Base == 8)) + { + return STATUS_INVALID_PARAMETER; + } + else if (((*Str > L'9') || (*Str < L'0')) && (Base == 10)) + { + return STATUS_INVALID_PARAMETER; + } + else if ( ((*Str > L'9') || (*Str < L'0')) && + ((towupper (*Str) > L'F') || (towupper (*Str) < L'A')) && + (Base == 16)) + { + return STATUS_INVALID_PARAMETER; + } + Str++; + } + + Str = String->Buffer + lenmin; + + if (Base == 0) + Base = 10; + + while (iswxdigit (*Str) && + (Val = iswdigit (*Str) ? *Str - L'0' : (iswlower (*Str) + ? towupper (*Str) : *Str) - L'A' + 10) < Base) + { + *Value = *Value * Base + Val; + Str++; + } + + if (addneg == TRUE) + *Value *= -1; + + return STATUS_SUCCESS; +} + + + +/* + * @implemented + * + * RETURNS + * Bytes necessary for the conversion including nullterm. + */ +ULONG +STDCALL +RtlUnicodeStringToOemSize( + IN PUNICODE_STRING UnicodeString) +{ + ULONG Size; + + RtlUnicodeToMultiByteSize (&Size, + UnicodeString->Buffer, + UnicodeString->Length); + + return Size+1; //NB: incl. nullterm +} + + +/* + * @implemented + * + + * NOTES + * See RtlpUnicodeStringToAnsiString + */ +NTSTATUS +STDCALL +RtlUnicodeStringToAnsiString( + IN OUT PANSI_STRING AnsiDest, + IN PUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString) +{ + return RtlpUnicodeStringToAnsiString( + AnsiDest, + UniSource, + AllocateDestinationString, + NonPagedPool); +} + + +/* + * private + * + * NOTES + * This function always writes a terminating '\0'. + * It performs a partial copy if ansi is too small. + */ +NTSTATUS +FASTCALL +RtlpUnicodeStringToAnsiString( + IN OUT PANSI_STRING AnsiDest, + IN PUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString, + IN POOL_TYPE PoolType) +{ + NTSTATUS Status = STATUS_SUCCESS; + ULONG Length; //including nullterm + + if (NlsMbCodePageTag == TRUE) + { + Length = RtlUnicodeStringToAnsiSize(UniSource); + } + else + Length = (UniSource->Length / sizeof(WCHAR)) + sizeof(CHAR); + + AnsiDest->Length = Length - sizeof(CHAR); + + if (AllocateDestinationString) + { + AnsiDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_ASTR); + if (AnsiDest->Buffer == NULL) + return STATUS_NO_MEMORY; + + AnsiDest->MaximumLength = Length; + } + else if (AnsiDest->MaximumLength == 0) + { + return STATUS_BUFFER_TOO_SMALL; + } + else if (Length > AnsiDest->MaximumLength) + { + //make room for nullterm + AnsiDest->Length = AnsiDest->MaximumLength - sizeof(CHAR); + } + + Status = RtlUnicodeToMultiByteN (AnsiDest->Buffer, + AnsiDest->Length, + NULL, + UniSource->Buffer, + UniSource->Length); + + if (!NT_SUCCESS(Status) && AllocateDestinationString) + { + ExFreePool (AnsiDest->Buffer); + return Status; + } + + AnsiDest->Buffer[AnsiDest->Length] = 0; + return Status; +} + + +/* + * @implemented + * + * NOTES + * See RtlpOemStringToUnicodeString + */ +NTSTATUS +STDCALL +RtlOemStringToUnicodeString( + IN OUT PUNICODE_STRING UniDest, + IN POEM_STRING OemSource, + IN BOOLEAN AllocateDestinationString) +{ + return RtlpOemStringToUnicodeString( + UniDest, + OemSource, + AllocateDestinationString, + NonPagedPool); +} + + +/* + * private + * + * NOTES + * This function always writes a terminating '\0'. + * Does NOT perform a partial copy if unicode is too small! + */ +NTSTATUS +FASTCALL +RtlpOemStringToUnicodeString( + IN OUT PUNICODE_STRING UniDest, + IN POEM_STRING OemSource, + IN BOOLEAN AllocateDestinationString, + IN POOL_TYPE PoolType) +{ + NTSTATUS Status; + ULONG Length; //including nullterm + + if (NlsMbOemCodePageTag == TRUE) + Length = RtlOemStringToUnicodeSize(OemSource); + else + Length = (OemSource->Length * sizeof(WCHAR)) + sizeof(WCHAR); + + if (Length > 0xffff) + return STATUS_INVALID_PARAMETER_2; + + UniDest->Length = (WORD)(Length - sizeof(WCHAR)); + + if (AllocateDestinationString) + { + UniDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_USTR); + if (UniDest->Buffer == NULL) + return STATUS_NO_MEMORY; + + UniDest->MaximumLength = Length; + } + else if (Length > UniDest->MaximumLength) + { + DPRINT("STATUS_BUFFER_TOO_SMALL\n"); + return STATUS_BUFFER_TOO_SMALL; + } + + //FIXME: Do we need this????? -Gunnar + RtlZeroMemory (UniDest->Buffer, + UniDest->Length); + + Status = RtlOemToUnicodeN (UniDest->Buffer, + UniDest->Length, + NULL, + OemSource->Buffer, + OemSource->Length); + + if (!NT_SUCCESS(Status) && AllocateDestinationString) + { + ExFreePool (UniDest->Buffer); + return Status; + } + + UniDest->Buffer[UniDest->Length / sizeof(WCHAR)] = 0; + return STATUS_SUCCESS; +} + + +/* + * @implemented + * + * NOTES + * See RtlpUnicodeStringToOemString. + */ +NTSTATUS +STDCALL +RtlUnicodeStringToOemString( + IN OUT POEM_STRING OemDest, + IN PUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString) +{ + return RtlpUnicodeStringToOemString( + OemDest, + UniSource, + AllocateDestinationString, + NonPagedPool); +} + + + +/* + * private + * + * NOTES + * This function always '\0' terminates the string returned. + */ +NTSTATUS +FASTCALL +RtlpUnicodeStringToOemString( + IN OUT POEM_STRING OemDest, + IN PUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString, + IN POOL_TYPE PoolType) +{ + NTSTATUS Status = STATUS_SUCCESS; + ULONG Length; //including nullterm + + if (NlsMbOemCodePageTag == TRUE) + Length = RtlUnicodeStringToAnsiSize (UniSource); + else + Length = (UniSource->Length / sizeof(WCHAR)) + sizeof(CHAR); + + if (Length > 0x0000FFFF) + return STATUS_INVALID_PARAMETER_2; + + OemDest->Length = (WORD)(Length - sizeof(CHAR)); + + if (AllocateDestinationString) + { + OemDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_OSTR); + if (OemDest->Buffer == NULL) + return STATUS_NO_MEMORY; + + OemDest->MaximumLength = Length; + } + else if (OemDest->MaximumLength == 0) + { + return STATUS_BUFFER_TOO_SMALL; + } + else if (Length > OemDest->MaximumLength) + { + //make room for nullterm + OemDest->Length = OemDest->MaximumLength - sizeof(CHAR); + } + + Status = RtlUnicodeToOemN (OemDest->Buffer, + OemDest->Length, + NULL, + UniSource->Buffer, + UniSource->Length); + + if (!NT_SUCCESS(Status) && AllocateDestinationString) + { + ExFreePool(OemDest->Buffer); + return Status; + } + + OemDest->Buffer[OemDest->Length] = 0; + return Status; +} + + + +#define ITU_IMPLEMENTED_TESTS (IS_TEXT_UNICODE_ODD_LENGTH|IS_TEXT_UNICODE_SIGNATURE) + + +/* + * @implemented + * + * RETURNS + * The length of the string if all tests were passed, 0 otherwise. + */ +ULONG STDCALL +RtlIsTextUnicode (PVOID Buffer, + ULONG Length, + ULONG *Flags) +{ + PWSTR s = Buffer; + ULONG in_flags = (ULONG)-1; + ULONG out_flags = 0; + + if (Length == 0) + goto done; + + if (Flags != 0) + in_flags = *Flags; + + /* + * Apply various tests to the text string. According to the + * docs, each test "passed" sets the corresponding flag in + * the output flags. But some of the tests are mutually + * exclusive, so I don't see how you could pass all tests ... + */ + + /* Check for an odd length ... pass if even. */ + if (!(Length & 1)) + out_flags |= IS_TEXT_UNICODE_ODD_LENGTH; + + /* Check for the BOM (byte order mark). */ + if (*s == 0xFEFF) + out_flags |= IS_TEXT_UNICODE_SIGNATURE; + +#if 0 + /* Check for the reverse BOM (byte order mark). */ + if (*s == 0xFFFE) + out_flags |= IS_TEXT_UNICODE_REVERSE_SIGNATURE; +#endif + + /* FIXME: Add more tests */ + + /* + * Check whether the string passed all of the tests. + */ + in_flags &= ITU_IMPLEMENTED_TESTS; + if ((out_flags & in_flags) != in_flags) + Length = 0; + +done: + if (Flags != 0) + *Flags = out_flags; + + return Length; +} + + +/* + * @implemented + * + * NOTES + * See RtlpOemStringToCountedUnicodeString + */ +NTSTATUS +STDCALL +RtlOemStringToCountedUnicodeString( + IN OUT PUNICODE_STRING UniDest, + IN POEM_STRING OemSource, + IN BOOLEAN AllocateDestinationString) +{ + return RtlpOemStringToCountedUnicodeString( + UniDest, + OemSource, + AllocateDestinationString, + NonPagedPool); +} + + +/* + * private + * + + * NOTES + * Same as RtlOemStringToUnicodeString but doesn't write terminating null + * A partial copy is NOT performed if the dest buffer is too small! + */ +NTSTATUS +FASTCALL +RtlpOemStringToCountedUnicodeString( + IN OUT PUNICODE_STRING UniDest, + IN POEM_STRING OemSource, + IN BOOLEAN AllocateDestinationString, + IN POOL_TYPE PoolType) +{ + NTSTATUS Status; + ULONG Length; //excluding nullterm + + if (NlsMbCodePageTag == TRUE) + Length = RtlOemStringToUnicodeSize(OemSource) - sizeof(WCHAR); + else + Length = OemSource->Length * sizeof(WCHAR); + + if (Length > 65535) + return STATUS_INVALID_PARAMETER_2; + + if (AllocateDestinationString == TRUE) + { + UniDest->Buffer = ExAllocatePoolWithTag (PoolType, Length, TAG_USTR); + if (UniDest->Buffer == NULL) + return STATUS_NO_MEMORY; + + UniDest->MaximumLength = Length; + } + else if (Length > UniDest->MaximumLength) + { + return STATUS_BUFFER_TOO_SMALL; + } + + UniDest->Length = Length; + + Status = RtlOemToUnicodeN (UniDest->Buffer, + UniDest->Length, + NULL, + OemSource->Buffer, + OemSource->Length); + + if (!NT_SUCCESS(Status) && AllocateDestinationString) + { + ExFreePool (UniDest->Buffer); + return Status; + } + + return Status; +} + + +//FIXME: sjekk returnverdi og returtype. Wine koflikter mht. returtype for EqualString og EqualComputer--- +/* + * @implemented + * + * RETURNS + * 0 if the names are equal, non-zero otherwise. + * + * NOTES + * The comparison is case insensitive. + */ +BOOLEAN +STDCALL +RtlEqualComputerName( + IN PUNICODE_STRING ComputerName1, + IN PUNICODE_STRING ComputerName2) +{ + OEM_STRING OemString1; + OEM_STRING OemString2; + BOOLEAN Result = FALSE; + + if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString( &OemString1, ComputerName1, TRUE ))) + { + if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString( &OemString2, ComputerName2, TRUE ))) + { + Result = RtlEqualString( &OemString1, &OemString2, FALSE ); + RtlFreeOemString( &OemString2 ); + } + RtlFreeOemString( &OemString1 ); + } + + return Result; +} + +//FIXME: sjekk returnverdi og returtype. Wine koflikter mht. returtype for EqualString og EqualComputer--- +/* + * @implemented + * + * RETURNS + * 0 if the names are equal, non-zero otherwise. + * + * NOTES + * The comparison is case insensitive. + */ +BOOLEAN +STDCALL +RtlEqualDomainName ( + IN PUNICODE_STRING DomainName1, + IN PUNICODE_STRING DomainName2 +) +{ + return RtlEqualComputerName(DomainName1, DomainName2); +} + + +/* + * @implemented + */ +/* +BOOLEAN +STDCALL +RtlEqualDomainName ( + IN PUNICODE_STRING DomainName1, + IN PUNICODE_STRING DomainName2 +) +{ + OEM_STRING OemString1; + OEM_STRING OemString2; + BOOLEAN Result; + + RtlUpcaseUnicodeStringToOemString (&OemString1, + DomainName1, + TRUE); + RtlUpcaseUnicodeStringToOemString (&OemString2, + DomainName2, + TRUE); + + Result = RtlEqualString (&OemString1, + &OemString2, + FALSE); + + RtlFreeOemString (&OemString1); + RtlFreeOemString (&OemString2); + + return Result; + +} +*/ + +/* + * @implemented + * + * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45 + * + * Convert a string representation of a GUID into a GUID. + * + * PARAMS + * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" + * guid [O] Destination for the converted GUID + * + * RETURNS + * Success: STATUS_SUCCESS. guid contains the converted value. + * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format. + * + * SEE ALSO + * See RtlStringFromGUID. + */ +NTSTATUS +STDCALL +RtlGUIDFromString( + IN UNICODE_STRING *str, + OUT GUID* guid +) +{ + int i = 0; + const WCHAR *lpszCLSID = str->Buffer; + BYTE* lpOut = (BYTE*)guid; + + //TRACE("(%s,%p)\n", debugstr_us(str), guid); + + /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} + * to memory: DWORD... WORD WORD BYTES............ + */ + while (i < 37) + { + switch (i) + { + case 0: + if (*lpszCLSID != '{') + return STATUS_INVALID_PARAMETER; + break; + + case 9: + case 14: + case 19: + case 24: + if (*lpszCLSID != '-') + return STATUS_INVALID_PARAMETER; + break; + + case 37: + if (*lpszCLSID != '}') + return STATUS_INVALID_PARAMETER; + break; + + default: + { + WCHAR ch = *lpszCLSID, ch2 = lpszCLSID[1]; + unsigned char byte; + + /* Read two hex digits as a byte value */ + if (ch >= '0' && ch <= '9') + ch = ch - '0'; + else if (ch >= 'a' && ch <= 'f') + ch = ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + ch = ch - 'A' + 10; + else + return STATUS_INVALID_PARAMETER; + + if (ch2 >= '0' && ch2 <= '9') + ch2 = ch2 - '0'; + else if (ch2 >= 'a' && ch2 <= 'f') + ch2 = ch2 - 'a' + 10; + else if (ch2 >= 'A' && ch2 <= 'F') + ch2 = ch2 - 'A' + 10; + else + return STATUS_INVALID_PARAMETER; + + byte = ch << 4 | ch2; + + switch (i) + { +#ifndef WORDS_BIGENDIAN + /* For Big Endian machines, we store the data such that the + * dword/word members can be read as DWORDS and WORDS correctly. */ + /* Dword */ + case 1: + lpOut[3] = byte; + break; + case 3: + lpOut[2] = byte; + break; + case 5: + lpOut[1] = byte; + break; + case 7: + lpOut[0] = byte; + lpOut += 4; + break; + /* Word */ + case 10: + case 15: + lpOut[1] = byte; + break; + case 12: + case 17: + lpOut[0] = byte; + lpOut += 2; + break; +#endif + /* Byte */ + default: + lpOut[0] = byte; + lpOut++; + break; + } + lpszCLSID++; /* Skip 2nd character of byte */ + i++; + } + } + lpszCLSID++; + i++; + } + + return STATUS_SUCCESS; +} + + +/* + * @unimplemented + */ +NTSTATUS STDCALL +RtlInt64ToUnicodeString (IN ULONGLONG Value, + IN ULONG Base, + OUT PUNICODE_STRING String) +{ + return STATUS_NOT_IMPLEMENTED; +} + + +/* + * @implemented + */ +VOID +STDCALL +RtlEraseUnicodeString( + IN PUNICODE_STRING String) +{ + if (String->Buffer == NULL) + return; + + if (String->MaximumLength == 0) + return; + + memset (String->Buffer, + 0, + String->MaximumLength); + + String->Length = 0; +} + + + +/* + * @implemented + * + * NOTES + * See RtlpUnicodeStringToCountedOemString. + */ +NTSTATUS +STDCALL +RtlUnicodeStringToCountedOemString( + IN OUT POEM_STRING OemDest, + IN PUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString) +{ + return RtlpUnicodeStringToCountedOemString( + OemDest, + UniSource, + AllocateDestinationString, + NonPagedPool); +} + +/* + * private + * + * NOTES + * Same as RtlUnicodeStringToOemString but doesn't write terminating null + * Does a partial copy if the dest buffer is too small + */ +NTSTATUS +FASTCALL +RtlpUnicodeStringToCountedOemString( + IN OUT POEM_STRING OemDest, + IN PUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString, + IN POOL_TYPE PoolType) +{ + NTSTATUS Status; + ULONG Length; //excluding nullterm + + if (NlsMbOemCodePageTag == TRUE) + Length = RtlUnicodeStringToAnsiSize(UniSource) - sizeof(CHAR); + else + Length = (UniSource->Length / sizeof(WCHAR)); + + if (Length > 0x0000FFFF) + return STATUS_INVALID_PARAMETER_2; + + OemDest->Length = (WORD)(Length); + + if (AllocateDestinationString) + { + OemDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_OSTR); + if (OemDest->Buffer == NULL) + return STATUS_NO_MEMORY; + + OemDest->MaximumLength = Length; + } + else if (OemDest->MaximumLength == 0) + { + return STATUS_BUFFER_TOO_SMALL; + } + else if (Length > OemDest->MaximumLength) + { + OemDest->Length = OemDest->MaximumLength; + } + + Status = RtlUnicodeToOemN (OemDest->Buffer, + OemDest->Length, + NULL, + UniSource->Buffer, + UniSource->Length); + + if (!NT_SUCCESS(Status) && AllocateDestinationString) + { + ExFreePool(OemDest->Buffer); + } + + return Status; +} + + +/* + * @implemented + */ +NTSTATUS +STDCALL +RtlLargeIntegerToChar( + IN PLARGE_INTEGER Value, + IN ULONG Base, + IN ULONG Length, + IN OUT PCHAR String) +{ + ULONG Radix; + CHAR temp[65]; + ULONGLONG v = Value->QuadPart; + ULONG i; + PCHAR tp; + PCHAR sp; + + Radix = Base; + if (Radix == 0) + Radix = 10; + + if ((Radix != 2) && (Radix != 8) && + (Radix != 10) && (Radix != 16)) + return STATUS_INVALID_PARAMETER; + + tp = temp; + while (v || tp == temp) + { + i = v % Radix; + v = v / Radix; + if (i < 10) + *tp = i + '0'; + else + *tp = i + 'a' - 10; + tp++; + } + + if (tp - temp >= Length) + return STATUS_BUFFER_TOO_SMALL; + + sp = String; + while (tp > temp) + *sp++ = *--tp; + *sp = 0; + + return STATUS_SUCCESS; +} + + + +/* + * @implemented + * + * NOTES + * See RtlpUpcaseUnicodeString + */ +NTSTATUS +STDCALL +RtlUpcaseUnicodeString( + IN OUT PUNICODE_STRING UniDest, + IN PCUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString) +{ + + return RtlpUpcaseUnicodeString( + UniDest, + UniSource, + AllocateDestinationString, + NonPagedPool); +} + + +/* + * private + * + * NOTES + * dest is never '\0' terminated because it may be equal to src, and src + * might not be '\0' terminated. dest->Length is only set upon success. + */ +NTSTATUS +FASTCALL +RtlpUpcaseUnicodeString( + IN OUT PUNICODE_STRING UniDest, + IN PCUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString, + IN POOL_TYPE PoolType) +{ + ULONG i; + PWCHAR Src, Dest; + + if (AllocateDestinationString == TRUE) + { + UniDest->MaximumLength = UniSource->Length; + UniDest->Buffer = ExAllocatePoolWithTag(PoolType, UniDest->MaximumLength, TAG_USTR); + if (UniDest->Buffer == NULL) + return STATUS_NO_MEMORY; + } + else if (UniSource->Length > UniDest->MaximumLength) + { + return STATUS_BUFFER_TOO_SMALL; + } + + UniDest->Length = UniSource->Length; + + Src = UniSource->Buffer; + Dest = UniDest->Buffer; + for (i = 0; i < UniSource->Length / sizeof(WCHAR); i++) + { + *Dest = RtlUpcaseUnicodeChar (*Src); + Dest++; + Src++; + } + + return STATUS_SUCCESS; +} + + + +/* + * @implemented + * + * NOTES + * See RtlpUpcaseUnicodeStringToAnsiString + */ +NTSTATUS +STDCALL +RtlUpcaseUnicodeStringToAnsiString( + IN OUT PANSI_STRING AnsiDest, + IN PUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString) +{ + return RtlpUpcaseUnicodeStringToAnsiString( + AnsiDest, + UniSource, + AllocateDestinationString, + NonPagedPool); +} + +/* + * private + * + * NOTES + * This function always writes a terminating '\0'. + * It performs a partial copy if ansi is too small. + */ +NTSTATUS +FASTCALL +RtlpUpcaseUnicodeStringToAnsiString( + IN OUT PANSI_STRING AnsiDest, + IN PUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString, + IN POOL_TYPE PoolType) +{ + NTSTATUS Status; + ULONG Length; //including nullterm + + if (NlsMbCodePageTag == TRUE) + Length = RtlUnicodeStringToAnsiSize(UniSource); + else + Length = (UniSource->Length / sizeof(WCHAR)) + sizeof(CHAR); + + if (Length > 0x0000FFFF) + return STATUS_INVALID_PARAMETER_2; + + AnsiDest->Length = (WORD)(Length - sizeof(CHAR)); + + if (AllocateDestinationString) + { + AnsiDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_ASTR); + if (AnsiDest->Buffer == NULL) + return STATUS_NO_MEMORY; + + AnsiDest->MaximumLength = Length; + } + else if (AnsiDest->MaximumLength == 0) + { + return STATUS_BUFFER_TOO_SMALL; + } + else if (Length > AnsiDest->MaximumLength) + { + //make room for nullterm + AnsiDest->Length = AnsiDest->MaximumLength - sizeof(CHAR); + } + + //FIXME: do we need this??????? -Gunnar + RtlZeroMemory (AnsiDest->Buffer, + AnsiDest->Length); + + Status = RtlUpcaseUnicodeToMultiByteN (AnsiDest->Buffer, + AnsiDest->Length, + NULL, + UniSource->Buffer, + UniSource->Length); + + if (!NT_SUCCESS(Status) && AllocateDestinationString) + { + ExFreePool(AnsiDest->Buffer); + return Status; + } + + AnsiDest->Buffer[AnsiDest->Length] = 0; + return Status; +} + + + +/* + * @implemented + * + * NOTES + * See RtlpUpcaseUnicodeStringToCountedOemString + */ +NTSTATUS +STDCALL +RtlUpcaseUnicodeStringToCountedOemString( + IN OUT POEM_STRING OemDest, + IN PUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString) +{ + return RtlpUpcaseUnicodeStringToCountedOemString( + OemDest, + UniSource, + AllocateDestinationString, + NonPagedPool); +} + + + +/* + * private + * + * NOTES + * Same as RtlUpcaseUnicodeStringToOemString but doesn't write terminating null + * It performs a partial copy if oem is too small. + */ +NTSTATUS +FASTCALL +RtlpUpcaseUnicodeStringToCountedOemString( + IN OUT POEM_STRING OemDest, + IN PUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString, + IN POOL_TYPE PoolType) +{ + NTSTATUS Status; + ULONG Length; //excluding nullterm + + if (NlsMbCodePageTag == TRUE) + Length = RtlUnicodeStringToAnsiSize(UniSource) - sizeof(CHAR); + else + Length = UniSource->Length / sizeof(WCHAR); + + if (Length > 0x0000FFFF) + return(STATUS_INVALID_PARAMETER_2); + + OemDest->Length = (WORD)(Length); + + if (AllocateDestinationString) + { + OemDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_OSTR); + if (OemDest->Buffer == NULL) + return(STATUS_NO_MEMORY); + + //FIXME: Do we need this????? + RtlZeroMemory (OemDest->Buffer, Length); + + OemDest->MaximumLength = (WORD)Length; + } + else if (OemDest->MaximumLength == 0) + { + return(STATUS_BUFFER_TOO_SMALL); + } + else if (Length > OemDest->MaximumLength) + { + OemDest->Length = OemDest->MaximumLength; + } + + Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer, + OemDest->Length, + NULL, + UniSource->Buffer, + UniSource->Length); + + if (!NT_SUCCESS(Status) && AllocateDestinationString) + { + ExFreePool(OemDest->Buffer); + return Status; + } + + return Status; +} + + +/* + * @implemented + * NOTES + * See RtlpUpcaseUnicodeStringToOemString + */ +NTSTATUS +STDCALL +RtlUpcaseUnicodeStringToOemString ( + IN OUT POEM_STRING OemDest, + IN PUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString +) +{ + return RtlpUpcaseUnicodeStringToOemString( + OemDest, + UniSource, + AllocateDestinationString, + NonPagedPool); +} + + +/* + * private + * + * NOTES + * Oem string is allways nullterminated + * It performs a partial copy if oem is too small. + */ +NTSTATUS +FASTCALL +RtlpUpcaseUnicodeStringToOemString ( + IN OUT POEM_STRING OemDest, + IN PUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString, + IN POOL_TYPE PoolType +) +{ + NTSTATUS Status; + ULONG Length; //including nullterm + + if (NlsMbOemCodePageTag == TRUE) + Length = RtlUnicodeStringToAnsiSize(UniSource); + else + Length = (UniSource->Length / sizeof(WCHAR)) + sizeof(CHAR); + + if (Length > 0x0000FFFF) + return STATUS_INVALID_PARAMETER_2; + + OemDest->Length = (WORD)(Length - sizeof(CHAR)); + + if (AllocateDestinationString) + { + OemDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_OSTR); + if (OemDest->Buffer == NULL) + return STATUS_NO_MEMORY; + + //FIXME: Do we need this???? + RtlZeroMemory (OemDest->Buffer, Length); + + OemDest->MaximumLength = (WORD)Length; + } + else if (OemDest->MaximumLength == 0) + { + return STATUS_BUFFER_OVERFLOW; + } + else if (Length > OemDest->MaximumLength) + { + //make room for nullterm + OemDest->Length = OemDest->MaximumLength - sizeof(CHAR); + } + + Status = RtlUpcaseUnicodeToOemN (OemDest->Buffer, + OemDest->Length, + NULL, + UniSource->Buffer, + UniSource->Length); + + if (!NT_SUCCESS(Status) && AllocateDestinationString) + { + ExFreePool(OemDest->Buffer); + return Status; + } + + OemDest->Buffer[OemDest->Length] = 0; + return Status; +} + + +/* + * @implemented + * + * RETURNS + * Bytes calculated including nullterm + */ +ULONG +STDCALL +RtlOemStringToUnicodeSize(IN POEM_STRING OemString) +{ + ULONG Size; + + //this function returns size including nullterm + RtlMultiByteToUnicodeSize(&Size, + OemString->Buffer, + OemString->Length); + + return(Size); +} + + + +/* + * @implemented + */ +NTSTATUS +STDCALL +RtlStringFromGUID (IN REFGUID Guid, + OUT PUNICODE_STRING GuidString) +{ + STATIC CONST PWCHAR Hex = L"0123456789ABCDEF"; + WCHAR Buffer[40]; + PWCHAR BufferPtr; + ULONG i; + + if (Guid == NULL) + { + return STATUS_INVALID_PARAMETER; + } + + swprintf (Buffer, + L"{%08lX-%04X-%04X-%02X%02X-", + Guid->Data1, + Guid->Data2, + Guid->Data3, + Guid->Data4[0], + Guid->Data4[1]); + BufferPtr = Buffer + 25; + + /* 6 hex bytes */ + for (i = 2; i < 8; i++) + { + *BufferPtr++ = Hex[Guid->Data4[i] >> 4]; + *BufferPtr++ = Hex[Guid->Data4[i] & 0xf]; + } + + *BufferPtr++ = L'}'; + *BufferPtr++ = L'\0'; + + return RtlCreateUnicodeString (GuidString, Buffer); +} + + +/* + * @implemented + * + * RETURNS + * Bytes calculated including nullterm + */ +ULONG +STDCALL +RtlUnicodeStringToAnsiSize( + IN PUNICODE_STRING UnicodeString) +{ + ULONG Size; + + //this function return size without nullterm! + RtlUnicodeToMultiByteSize (&Size, + UnicodeString->Buffer, + UnicodeString->Length); + + return Size + sizeof(CHAR); //NB: incl. nullterm +} + + + + +/* + * @implemented + */ +LONG +STDCALL +RtlCompareUnicodeString( + IN PUNICODE_STRING String1, + IN PUNICODE_STRING String2, + IN BOOLEAN CaseInsensitive) +{ + ULONG len1, len2; + PWCHAR s1, s2; + WCHAR c1, c2; + + if (String1 && String2) + { + len1 = String1->Length / sizeof(WCHAR); + len2 = String2->Length / sizeof(WCHAR); + s1 = String1->Buffer; + s2 = String2->Buffer; + + if (s1 && s2) + { + if (CaseInsensitive) + { + while (1) + { + c1 = len1-- ? RtlUpcaseUnicodeChar (*s1++) : 0; + c2 = len2-- ? RtlUpcaseUnicodeChar (*s2++) : 0; + if (!c1 || !c2 || c1 != c2) + return c1 - c2; + } + } + else + { + while (1) + { + c1 = len1-- ? *s1++ : 0; + c2 = len2-- ? *s2++ : 0; + if (!c1 || !c2 || c1 != c2) + return c1 - c2; + } + } + } + } + + return 0; +} + + +/* + * @implemented + */ +VOID +STDCALL +RtlCopyString( + IN OUT PSTRING DestinationString, + IN PSTRING SourceString) +{ + ULONG copylen; + + if(SourceString == NULL) + { + DestinationString->Length = 0; + return; + } + + copylen = min (DestinationString->MaximumLength - sizeof(CHAR), + SourceString->Length); + + memcpy(DestinationString->Buffer, SourceString->Buffer, copylen); + DestinationString->Buffer[copylen] = 0; + DestinationString->Length = copylen; +} + + + +/* + * @implemented + */ +VOID +STDCALL +RtlCopyUnicodeString( + IN OUT PUNICODE_STRING DestinationString, + IN PUNICODE_STRING SourceString) +{ + ULONG copylen; + + if (SourceString == NULL) + { + DestinationString->Length = 0; + return; + } + + copylen = min (DestinationString->MaximumLength - sizeof(WCHAR), + SourceString->Length); + memcpy(DestinationString->Buffer, SourceString->Buffer, copylen); + DestinationString->Buffer[copylen / sizeof(WCHAR)] = 0; + DestinationString->Length = copylen; +} + + +/* + * @implemented + * + * NOTES + * See RtlpCreateUnicodeString + */ +BOOLEAN +STDCALL +RtlCreateUnicodeString( + IN OUT PUNICODE_STRING UniDest, + IN PWSTR Source) +{ + + DPRINT("RtlCreateUnicodeString\n"); + return RtlpCreateUnicodeString(UniDest, Source, NonPagedPool); +} + + +/* + * private + */ +BOOLEAN +FASTCALL +RtlpCreateUnicodeString( + IN OUT PUNICODE_STRING UniDest, + IN PWSTR Source, + IN POOL_TYPE PoolType) +{ + ULONG Length; + + Length = (wcslen (Source) + 1) * sizeof(WCHAR); + + UniDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_USTR); + if (UniDest->Buffer == NULL) + return FALSE; + + memmove (UniDest->Buffer, + Source, + Length); + + UniDest->MaximumLength = Length; + UniDest->Length = Length - sizeof (WCHAR); + + return TRUE; +} + + + +/* + * @implemented + */ +BOOLEAN +STDCALL +RtlCreateUnicodeStringFromAsciiz( + OUT PUNICODE_STRING Destination, + IN PCSZ Source) +{ + ANSI_STRING AnsiString; + NTSTATUS Status; + + RtlInitAnsiString (&AnsiString, + Source); + + Status = RtlAnsiStringToUnicodeString (Destination, + &AnsiString, + TRUE); + + return NT_SUCCESS(Status); +} + + + +/* + * @implemented + * + * NOTES + * See RtlpDowncaseUnicodeString + */ +NTSTATUS STDCALL +RtlDowncaseUnicodeString( + IN OUT PUNICODE_STRING UniDest, + IN PUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString) +{ + return RtlpDowncaseUnicodeString( + UniDest, + UniSource, + AllocateDestinationString, + NonPagedPool); +} + + +/* + * private + * + * NOTES + * Dest is never '\0' terminated because it may be equal to src, and src + * might not be '\0' terminated. + * Dest->Length is only set upon success. + */ +NTSTATUS +FASTCALL +RtlpDowncaseUnicodeString( + IN OUT PUNICODE_STRING UniDest, + IN PUNICODE_STRING UniSource, + IN BOOLEAN AllocateDestinationString, + IN POOL_TYPE PoolType) +{ + ULONG i; + PWCHAR Src, Dest; + + if (AllocateDestinationString) + { + UniDest->Buffer = ExAllocatePoolWithTag(PoolType, UniSource->Length, TAG_USTR); + if (UniDest->Buffer == NULL) + return STATUS_NO_MEMORY; + + UniDest->MaximumLength = UniSource->Length; + } + else if (UniSource->Length > UniDest->MaximumLength) + { + return STATUS_BUFFER_TOO_SMALL; + } + + UniDest->Length = UniSource->Length; + + Src = UniSource->Buffer; + Dest = UniDest->Buffer; + for (i=0; i < UniSource->Length / sizeof(WCHAR); i++) + { + if (*Src < L'A') + { + *Dest = *Src; + } + else if (*Src <= L'Z') + { + *Dest = (*Src + (L'a' - L'A')); + } + else + { + *Dest = RtlDowncaseUnicodeChar(*Src); + } + + Dest++; + Src++; + } + + return STATUS_SUCCESS; +} + + + +/* + * @implemented + * + * NOTES + * if src is NULL dest is unchanged. + * dest is '\0' terminated when the MaximumLength allowes it. + * When dest fits exactly in MaximumLength characters the '\0' is ommitted. + */ +NTSTATUS STDCALL +RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination, + IN PWSTR Source) +{ + ULONG slen; + + slen = wcslen(Source) * sizeof(WCHAR); + + if (Destination->Length + slen > Destination->MaximumLength) + return(STATUS_BUFFER_TOO_SMALL); + + memcpy((char*)Destination->Buffer + Destination->Length, Source, slen); + Destination->Length += slen; + /* append terminating '\0' if enough space */ + if( Destination->MaximumLength > Destination->Length ) + Destination->Buffer[Destination->Length / sizeof(WCHAR)] = 0; + + return(STATUS_SUCCESS); +} + + +/* + * @implemented + * + * NOTES + * See RtlpAnsiStringToUnicodeString + */ +NTSTATUS +STDCALL +RtlAnsiStringToUnicodeString( + IN OUT PUNICODE_STRING UniDest, + IN PANSI_STRING AnsiSource, + IN BOOLEAN AllocateDestinationString) +{ + return RtlpAnsiStringToUnicodeString( + UniDest, + AnsiSource, + AllocateDestinationString, + NonPagedPool); +} + + + +/* + * private + * + * NOTES + * This function always writes a terminating '\0'. + * If the dest buffer is too small a partial copy is NOT performed! + */ +NTSTATUS +FASTCALL +RtlpAnsiStringToUnicodeString( + IN OUT PUNICODE_STRING UniDest, + IN PANSI_STRING AnsiSource, + IN BOOLEAN AllocateDestinationString, + IN POOL_TYPE PoolType) +{ + NTSTATUS Status; + ULONG Length; //including nullterm + + if (NlsMbCodePageTag == TRUE) + Length = RtlAnsiStringToUnicodeSize(AnsiSource); + else + Length = (AnsiSource->Length * sizeof(WCHAR)) + sizeof(WCHAR); + + if (Length > 0xffff) + return STATUS_INVALID_PARAMETER_2; + + if (AllocateDestinationString == TRUE) + { + UniDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_USTR); + if (UniDest->Buffer == NULL) + return STATUS_NO_MEMORY; + + UniDest->MaximumLength = Length; + } + else if (Length > UniDest->MaximumLength) + { + DPRINT("STATUS_BUFFER_TOO_SMALL\n"); + return STATUS_BUFFER_TOO_SMALL; + } + + UniDest->Length = Length - sizeof(WCHAR); + + //FIXME: We don't need this??? -Gunnar + RtlZeroMemory (UniDest->Buffer, + UniDest->Length); + + Status = RtlMultiByteToUnicodeN (UniDest->Buffer, + UniDest->Length, + NULL, + AnsiSource->Buffer, + AnsiSource->Length); + + if (!NT_SUCCESS(Status) && AllocateDestinationString) + { + ExFreePool(UniDest->Buffer); + return Status; + } + + UniDest->Buffer[UniDest->Length / sizeof(WCHAR)] = 0; + return Status; +} + + + +/* + * @implemented + * + * NOTES + * if src is NULL dest is unchanged. + * dest is never '\0' terminated. + */ +NTSTATUS +STDCALL +RtlAppendAsciizToString( + IN OUT PSTRING Destination, + IN PCSZ Source) +{ + ULONG Length; + PCHAR Ptr; + + if (Source == NULL) + return STATUS_SUCCESS; + + Length = strlen (Source); + if (Destination->Length + Length >= Destination->MaximumLength) + return STATUS_BUFFER_TOO_SMALL; + + Ptr = Destination->Buffer + Destination->Length; + memmove (Ptr, + Source, + Length); + Ptr += Length; + *Ptr = 0; + + Destination->Length += Length; + + return STATUS_SUCCESS; +} + + +/* + * @implemented + */ +VOID STDCALL +RtlUpperString(PSTRING DestinationString, + PSTRING SourceString) +{ + ULONG Length; + ULONG i; + PCHAR Src; + PCHAR Dest; + + Length = min(SourceString->Length, + DestinationString->MaximumLength - 1); + + Src = SourceString->Buffer; + Dest = DestinationString->Buffer; + for (i = 0; i < Length; i++) + { + *Dest = RtlUpperChar(*Src); + Src++; + Dest++; + } + *Dest = 0; + + DestinationString->Length = SourceString->Length; +} + + +/* + * @implemented + */ +ULONG STDCALL +RtlxAnsiStringToUnicodeSize(IN PANSI_STRING AnsiString) +{ + return RtlAnsiStringToUnicodeSize(AnsiString); +} + + +/* + * @implemented + */ +ULONG STDCALL +RtlxOemStringToUnicodeSize(IN POEM_STRING OemString) +{ + return RtlOemStringToUnicodeSize((PANSI_STRING)OemString); +} + + + +/* + * @implemented + */ +ULONG STDCALL +RtlxUnicodeStringToAnsiSize(IN PUNICODE_STRING UnicodeString) +{ + return RtlUnicodeStringToAnsiSize(UnicodeString); +} + + +/* + * @implemented + */ +ULONG STDCALL +RtlxUnicodeStringToOemSize(IN PUNICODE_STRING UnicodeString) +{ + return RtlUnicodeStringToOemSize(UnicodeString); +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +RtlDuplicateUnicodeString( + INT AddNull, + IN PUNICODE_STRING SourceString, + PUNICODE_STRING DestinationString) +{ + if (SourceString == NULL || DestinationString == NULL) + return STATUS_INVALID_PARAMETER; + + + if (SourceString->Length == 0 && AddNull != 3) + { + DestinationString->Length = 0; + DestinationString->MaximumLength = 0; + DestinationString->Buffer = NULL; + } + else + { + unsigned int DestMaxLength = SourceString->Length; + + if (AddNull) + DestMaxLength += sizeof(UNICODE_NULL); + + DestinationString->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, DestMaxLength); + if (DestinationString->Buffer == NULL) + return STATUS_NO_MEMORY; + + RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length); + DestinationString->Length = SourceString->Length; + DestinationString->MaximumLength = DestMaxLength; + + if (AddNull) + DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0; + } + + return STATUS_SUCCESS; +} + +/* EOF */ diff --git a/reactos/lib/rtl/version.c b/reactos/lib/rtl/version.c new file mode 100644 index 00000000000..25604dece92 --- /dev/null +++ b/reactos/lib/rtl/version.c @@ -0,0 +1,68 @@ +/* + * ReactOS kernel + * Copyright (C) 2004 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: version.c,v 1.1 2004/05/31 19:29:02 gdalsnes Exp $ + * + * PROJECT: ReactOS kernel + * PURPOSE: Runtime code + * FILE: lib/rtl/version.c + * PROGRAMER: Filip Navara + */ + +/* INCLUDES *****************************************************************/ + +#define __USE_W32API + +#include +#include + +#define NDEBUG +#include + + +/* FUNCTIONS ****************************************************************/ + +NTSTATUS STDCALL +RtlGetVersion(RTL_OSVERSIONINFOW *Info) +{ + WCHAR CSDString[] = L"Service Pack 6"; + + if (Info->dwOSVersionInfoSize == sizeof(RTL_OSVERSIONINFOW) || + Info->dwOSVersionInfoSize == sizeof(RTL_OSVERSIONINFOEXW)) + { + Info->dwMajorVersion = 4; + Info->dwMinorVersion = 0; + Info->dwBuildNumber = 1381; + Info->dwPlatformId = VER_PLATFORM_WIN32_NT; + RtlCopyMemory(Info->szCSDVersion, CSDString, sizeof(CSDString)); + if (Info->dwOSVersionInfoSize == sizeof(RTL_OSVERSIONINFOEXW)) + { + RTL_OSVERSIONINFOEXW *InfoEx = (RTL_OSVERSIONINFOEXW *)Info; + InfoEx->wServicePackMajor = 6; + InfoEx->wServicePackMinor = 0; + InfoEx->wSuiteMask = 0; + InfoEx->wProductType = VER_NT_WORKSTATION; + } + + return STATUS_SUCCESS; + } + + return STATUS_INVALID_PARAMETER; +} + +/* EOF */