/* Editor Settings: expandtabs and use 4 spaces for indentation * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: * * -*- mode: c, c-basic-offset: 4 -*- */ /* * Copyright (c) Likewise Software. All rights Reserved. * * 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 program. If * not, see . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewise.com */ /* * Copyright (C) Likewise Software. All rights reserved. * * Module Name: * * rtlstring_unicode.c * * Abstract: * * Base UNICODE_STRING Functions * * Authors: Danilo Almeida (dalmeida@likewise.com) * */ #include "includes.h" #include #include #include #include VOID LwRtlUnicodeStringInit( OUT PUNICODE_STRING DestinationString, IN PCWSTR SourceString ) { size_t length = 0; if (SourceString) { length = wc16slen(SourceString); length = LW_MIN(length, LW_UNICODE_STRING_MAX_CHARS); length *= sizeof(SourceString[0]); } DestinationString->Buffer = (PWSTR) SourceString; DestinationString->Length = (USHORT) length; DestinationString->MaximumLength = DestinationString->Length + sizeof(SourceString[0]); } NTSTATUS LwRtlUnicodeStringInitEx( OUT PUNICODE_STRING DestinationString, IN PCWSTR SourceString ) { NTSTATUS status = STATUS_SUCCESS; size_t length = 0; if (SourceString) { length = wc16slen(SourceString); if (length > LW_UNICODE_STRING_MAX_CHARS) { status = STATUS_INVALID_PARAMETER; GOTO_CLEANUP(); } length *= sizeof(SourceString[0]); } DestinationString->Buffer = (PWSTR) SourceString; DestinationString->Length = (USHORT) length; DestinationString->MaximumLength = DestinationString->Length + sizeof(SourceString[0]); status = STATUS_SUCCESS; cleanup: if (!NT_SUCCESS(status)) { RtlZeroMemory(DestinationString, sizeof(*DestinationString)); } return status; } NTSTATUS LwRtlUnicodeStringAllocateFromAnsiString( OUT PUNICODE_STRING pNewString, IN PANSI_STRING pOriginalString ) { NTSTATUS status = 0; ANSI_STRING terminatedOriginalString = { 0 }; PSTR pszTerminatedString = NULL; UNICODE_STRING newString = { 0 }; if (LW_RTL_STRING_IS_NULL_TERMINATED(pOriginalString)) { pszTerminatedString = pOriginalString->Buffer; } else { // Since duplicate always does NULL-termination, we can // safely use the Buffer field as a WC16String. status = LwRtlAnsiStringDuplicate(&terminatedOriginalString, pOriginalString); GOTO_CLEANUP_ON_STATUS(status); pszTerminatedString = terminatedOriginalString.Buffer; } status = LwRtlUnicodeStringAllocateFromCString(&newString, pszTerminatedString); GOTO_CLEANUP_ON_STATUS(status); cleanup: if (!NT_SUCCESS(status)) { LwRtlUnicodeStringFree(&newString); } LwRtlAnsiStringFree(&terminatedOriginalString); *pNewString = newString; return status; } NTSTATUS LwRtlUnicodeStringAllocateFromWC16String( OUT PUNICODE_STRING pString, IN PCWSTR pszString ) { NTSTATUS status = 0; PWSTR pszNewString = NULL; UNICODE_STRING newString = { 0 }; status = RtlWC16StringDuplicate(&pszNewString, pszString); GOTO_CLEANUP_ON_STATUS(status); newString.Buffer = pszNewString; pszNewString = NULL; newString.Length = wc16slen(newString.Buffer) * sizeof(newString.Buffer[0]); newString.MaximumLength = newString.Length + sizeof(newString.Buffer[0]); cleanup: if (status) { RTL_FREE(&pszNewString); RtlUnicodeStringFree(&newString); } *pString = newString; return status; } NTSTATUS LwRtlUnicodeStringAllocateFromCString( OUT PUNICODE_STRING pString, IN PCSTR pszString ) { NTSTATUS status = 0; PWSTR pszNewString = NULL; UNICODE_STRING newString = { 0 }; status = RtlWC16StringAllocateFromCString(&pszNewString, pszString); GOTO_CLEANUP_ON_STATUS(status); newString.Buffer = pszNewString; pszNewString = NULL; newString.Length = wc16slen(newString.Buffer) * sizeof(newString.Buffer[0]); newString.MaximumLength = newString.Length + sizeof(newString.Buffer[0]); cleanup: if (status) { RTL_FREE(&pszNewString); RtlUnicodeStringFree(&newString); } *pString = newString; return status; } NTSTATUS LwRtlUnicodeStringDuplicate( OUT PUNICODE_STRING pNewString, IN PUNICODE_STRING pOriginalString ) { NTSTATUS status = 0; int EE = 0; UNICODE_STRING newString = { 0 }; if (!pOriginalString || !pNewString) { status = STATUS_INVALID_PARAMETER; GOTO_CLEANUP_ON_STATUS_EE(status, EE); } if (pOriginalString->Buffer && pOriginalString->Length > 0) { // Add a NULL anyhow. newString.Length = pOriginalString->Length; newString.MaximumLength = pOriginalString->Length + sizeof(pOriginalString->Buffer[0]); status = RTL_ALLOCATE(&newString.Buffer, WCHAR, newString.MaximumLength); GOTO_CLEANUP_ON_STATUS_EE(status, EE); memcpy(newString.Buffer, pOriginalString->Buffer, pOriginalString->Length); newString.Buffer[newString.Length/sizeof(newString.Buffer[0])] = 0; } cleanup: if (status) { RtlUnicodeStringFree(&newString); } *pNewString = newString; return status; } VOID LwRtlUnicodeStringFree( IN OUT PUNICODE_STRING pString ) { RTL_FREE(&pString->Buffer); pString->Length = pString->MaximumLength = 0; } BOOLEAN LwRtlUnicodeStringIsEqual( IN PUNICODE_STRING pString1, IN PUNICODE_STRING pString2, IN BOOLEAN bIsCaseSensitive ) { BOOLEAN bIsEqual = FALSE; // TODO--comparison -- need fix in libunistr... if (pString1->Length != pString2->Length) { GOTO_CLEANUP(); } else if (bIsCaseSensitive) { ULONG i; for (i = 0; i < pString1->Length / sizeof(pString1->Buffer[0]); i++) { if (pString1->Buffer[i] != pString2->Buffer[i]) { GOTO_CLEANUP(); } } } else { ULONG i; for (i = 0; i < pString1->Length / sizeof(pString1->Buffer[0]); i++) { wchar16_t c1[] = { pString1->Buffer[i], 0 }; wchar16_t c2[] = { pString2->Buffer[i], 0 }; wc16supper(c1); wc16supper(c2); if (c1[0] != c2[0]) { GOTO_CLEANUP(); } } } bIsEqual = TRUE; cleanup: return bIsEqual; } BOOLEAN LwRtlUnicodeStringIsPrefix( IN PUNICODE_STRING pPrefix, IN PUNICODE_STRING pString, IN BOOLEAN bIsCaseSensitive ) { BOOLEAN bIsPrefix = FALSE; UNICODE_STRING truncatedString = { 0 }; if (pPrefix->Length > pString->Length) { GOTO_CLEANUP(); } truncatedString.Buffer = pString->Buffer; truncatedString.Length = truncatedString.MaximumLength = pPrefix->Length; bIsPrefix = LwRtlUnicodeStringIsEqual(pPrefix, &truncatedString, bIsCaseSensitive); cleanup: return bIsPrefix; } NTSTATUS LwRtlUnicodeStringParseULONG( OUT PULONG pResult, IN PUNICODE_STRING pString, OUT PUNICODE_STRING pRemainingString ) { NTSTATUS status = STATUS_SUCCESS; ULONG64 value = 0; ULONG numChars = 0; ULONG index = 0; UNICODE_STRING remaining = { 0 }; if (!pString) { status = STATUS_INVALID_PARAMETER; GOTO_CLEANUP(); } numChars = LW_RTL_STRING_NUM_CHARS(pString); for (index = 0; ((index < numChars) && LwRtlIsDecimalDigit(pString->Buffer[index])); index++) { value = value * 10 + LwRtlDecimalDigitValue(pString->Buffer[index]); if (value > MAXULONG) { status = STATUS_INTEGER_OVERFLOW; GOTO_CLEANUP(); } } if (0 == index) { status = STATUS_NOT_FOUND; GOTO_CLEANUP(); } remaining.Buffer = &pString->Buffer[index]; remaining.Length = pString->Length - LW_PTR_OFFSET(pString->Buffer, remaining.Buffer); remaining.MaximumLength = remaining.Length; status = STATUS_SUCCESS; cleanup: if (!NT_SUCCESS(status)) { if (pString) { remaining = *pString; } } *pResult = (ULONG) value; *pRemainingString = remaining; return status; }