636 lines
14 KiB
C
636 lines
14 KiB
C
/*
|
|
* Rtl string functions
|
|
*
|
|
* Copyright 1996-1998 Marcus Meissner
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include "wine/winestring.h"
|
|
#include "crtdll.h"
|
|
#include "heap.h"
|
|
#include "winnls.h"
|
|
#include "debugtools.h"
|
|
#include "ntdll_misc.h"
|
|
#include "ntddk.h"
|
|
|
|
#include "casemap.h"
|
|
|
|
DEFAULT_DEBUG_CHANNEL(ntdll)
|
|
|
|
/* STRING FUNCTIONS */
|
|
|
|
/**************************************************************************
|
|
* NTDLL.towupper
|
|
*/
|
|
WCHAR CDECL NTDLL_towupper(WCHAR code)
|
|
{
|
|
const WCHAR * ptr = uprtable[HIBYTE(code)];
|
|
return ptr ? ptr[LOBYTE(code)] : code;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* NTDLL.towlower
|
|
*/
|
|
WCHAR CDECL NTDLL_towlower(WCHAR code)
|
|
{
|
|
const WCHAR * ptr = lwrtable[HIBYTE(code)];
|
|
return ptr ? ptr[LOBYTE(code)] : code;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* RtlInitString
|
|
*/
|
|
VOID WINAPI RtlInitString(PSTRING target,LPCSTR source)
|
|
{
|
|
TRACE("%p %p(%s)\n", target, source, debugstr_a(source));
|
|
|
|
target->Buffer = (LPSTR)source;
|
|
if (source)
|
|
{
|
|
target->Length = lstrlenA(source);
|
|
target->MaximumLength = target->Length+1;
|
|
}
|
|
else
|
|
{
|
|
target->Length = target->MaximumLength = 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* ANSI FUNCTIONS */
|
|
|
|
/**************************************************************************
|
|
* RtlInitAnsiString
|
|
*/
|
|
VOID WINAPI RtlInitAnsiString(
|
|
PANSI_STRING target,
|
|
LPCSTR source)
|
|
{
|
|
TRACE("%p %p(%s)\n", target, source, debugstr_a(source));
|
|
|
|
target->Buffer = (LPSTR)source;
|
|
if (source)
|
|
{
|
|
target->Length = lstrlenA(source);
|
|
target->MaximumLength = target->Length+1;
|
|
}
|
|
else
|
|
{
|
|
target->Length = target->MaximumLength = 0;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
* RtlFreeAnsiString
|
|
*/
|
|
VOID WINAPI RtlFreeAnsiString(
|
|
PANSI_STRING AnsiString)
|
|
{
|
|
TRACE("%p\n", AnsiString);
|
|
dump_AnsiString(AnsiString, TRUE);
|
|
|
|
if( AnsiString->Buffer )
|
|
HeapFree( GetProcessHeap(),0,AnsiString->Buffer );
|
|
}
|
|
|
|
|
|
|
|
/* UNICODE FUNCTIONS */
|
|
|
|
/**************************************************************************
|
|
* RtlInitUnicodeString [NTDLL.403]
|
|
*/
|
|
VOID WINAPI RtlInitUnicodeString(
|
|
PUNICODE_STRING target,
|
|
LPCWSTR source)
|
|
{
|
|
TRACE("%p %p(%s)\n", target, source, debugstr_w(source));
|
|
|
|
target->Buffer = (LPWSTR)source;
|
|
if (source)
|
|
{
|
|
target->Length = lstrlenW(source)*2;
|
|
target->MaximumLength = target->Length + 2;
|
|
}
|
|
else
|
|
{
|
|
target->Length = target->MaximumLength = 0;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
* RtlFreeUnicodeString [NTDLL.377]
|
|
*/
|
|
VOID WINAPI RtlFreeUnicodeString(
|
|
PUNICODE_STRING UnicodeString)
|
|
{
|
|
TRACE("%p\n", UnicodeString);
|
|
dump_UnicodeString(UnicodeString, TRUE);
|
|
|
|
if (UnicodeString->Buffer)
|
|
HeapFree(GetProcessHeap(),0,UnicodeString->Buffer);
|
|
}
|
|
|
|
/*
|
|
COMPARE FUNCTIONS
|
|
*/
|
|
|
|
/**************************************************************************
|
|
* RtlEqualUnicodeString
|
|
*/
|
|
BOOLEAN WINAPI RtlEqualUnicodeString(
|
|
IN PUNICODE_STRING s1,
|
|
IN PUNICODE_STRING s2,
|
|
IN BOOLEAN CaseInsensitive)
|
|
{
|
|
BOOLEAN ret;
|
|
TRACE("(%p,%p,%x)\n",s1,s2,CaseInsensitive);
|
|
dump_UnicodeString(s1, TRUE);
|
|
dump_UnicodeString(s2, TRUE);
|
|
|
|
if(!s1 || !s2 || !s1->Buffer || !s2->Buffer) return FALSE;
|
|
if (s1->Length != s2->Length) return FALSE;
|
|
|
|
if (CaseInsensitive)
|
|
ret = !CRTDLL__wcsnicmp(s1->Buffer,s2->Buffer,s1->Length/sizeof(WCHAR));
|
|
else
|
|
ret = !CRTDLL_wcsncmp(s1->Buffer,s2->Buffer,s1->Length/sizeof(WCHAR));
|
|
return ret;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* RtlCompareUnicodeString
|
|
*/
|
|
LONG WINAPI RtlCompareUnicodeString(
|
|
PUNICODE_STRING s1,
|
|
PUNICODE_STRING s2,
|
|
BOOLEAN CaseInsensitive)
|
|
{
|
|
LONG ret;
|
|
|
|
TRACE("(%p,%p,%x)\n",s1,s2,CaseInsensitive);
|
|
dump_UnicodeString(s1, TRUE);
|
|
dump_UnicodeString(s2, TRUE);
|
|
|
|
if(!s1 || !s2 || !s1->Buffer || !s2->Buffer) return FALSE;
|
|
|
|
if (s1->Length != s2->Length) return (s1->Length - s2->Length);
|
|
|
|
if (CaseInsensitive)
|
|
ret = CRTDLL__wcsnicmp(s1->Buffer,s2->Buffer,s1->Length/sizeof(WCHAR));
|
|
else
|
|
ret = CRTDLL_wcsncmp(s1->Buffer,s2->Buffer,s1->Length/sizeof(WCHAR));
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
COPY BETWEEN ANSI_STRING or UNICODE_STRING
|
|
there is no parameter checking, it just crashes
|
|
*/
|
|
|
|
/**************************************************************************
|
|
* RtlAnsiStringToUnicodeString
|
|
*
|
|
* NOTES:
|
|
* writes terminating 0
|
|
*/
|
|
NTSTATUS
|
|
WINAPI RtlAnsiStringToUnicodeString(
|
|
PUNICODE_STRING uni,
|
|
PANSI_STRING ansi,
|
|
BOOLEAN doalloc)
|
|
{
|
|
int len = ansi->Length * sizeof(WCHAR);
|
|
|
|
TRACE("%p %p %u\n",uni, ansi, doalloc);
|
|
dump_AnsiString(ansi, TRUE);
|
|
dump_UnicodeString(uni, FALSE);
|
|
|
|
if (len>0xfffe) return STATUS_INVALID_PARAMETER_2;
|
|
uni->Length = len;
|
|
if (doalloc)
|
|
{
|
|
uni->MaximumLength = len + sizeof(WCHAR);
|
|
uni->Buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,uni->MaximumLength);
|
|
if (!uni->Buffer) return STATUS_NO_MEMORY;
|
|
}
|
|
else if (len+sizeof(WCHAR) > uni->MaximumLength)
|
|
{
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
lstrcpynAtoW(uni->Buffer,ansi->Buffer,ansi->Length+1);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* RtlUpcaseUnicodeString
|
|
*
|
|
* NOTES:
|
|
* destination string is never 0-terminated because dest can be equal to src
|
|
* and src might be not 0-terminated
|
|
* dest.Length only set when success
|
|
*/
|
|
DWORD WINAPI RtlUpcaseUnicodeString(
|
|
PUNICODE_STRING dest,
|
|
PUNICODE_STRING src,
|
|
BOOLEAN doalloc)
|
|
{
|
|
int i, len = src->Length;
|
|
|
|
TRACE("(%p,%p,%x)\n",dest, src, doalloc);
|
|
dump_UnicodeString(dest, FALSE);
|
|
dump_UnicodeString(src, TRUE);
|
|
|
|
if (doalloc)
|
|
{
|
|
dest->Buffer = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
|
|
if (!dest->Buffer) return STATUS_NO_MEMORY;
|
|
dest->MaximumLength = len;
|
|
}
|
|
else if (len > dest->MaximumLength)
|
|
{
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
for (i=0; i < len/sizeof(WCHAR); i++)
|
|
{
|
|
dest->Buffer[i] = NTDLL_towupper(src->Buffer[i]);
|
|
}
|
|
dest->Length = len;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* RtlOemStringToUnicodeString
|
|
*
|
|
* NOTES
|
|
* writes terminating 0
|
|
* buffer must be bigger than (ansi->Length+1)*2
|
|
* if astr.Length > 0x7ffe it returns STATUS_INVALID_PARAMETER_2
|
|
*
|
|
* FIXME
|
|
* OEM to unicode
|
|
*/
|
|
NTSTATUS
|
|
WINAPI RtlOemStringToUnicodeString(
|
|
PUNICODE_STRING uni,
|
|
PSTRING ansi,
|
|
BOOLEAN doalloc)
|
|
{
|
|
int len = ansi->Length * sizeof(WCHAR);
|
|
|
|
if (len > 0xfffe) return STATUS_INVALID_PARAMETER_2;
|
|
|
|
uni->Length = len;
|
|
if (doalloc)
|
|
{
|
|
uni->Buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, len + sizeof(WCHAR));
|
|
if (!uni->Buffer) return STATUS_NO_MEMORY;
|
|
uni->MaximumLength = len + sizeof(WCHAR);
|
|
}
|
|
else if (len+1 > uni->MaximumLength )
|
|
{
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
lstrcpynAtoW(uni->Buffer,ansi->Buffer,ansi->Length+1);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* RtlUnicodeStringToOemString
|
|
*
|
|
* NOTES
|
|
* allocates uni->Length+1
|
|
* writes terminating 0
|
|
*/
|
|
NTSTATUS
|
|
WINAPI RtlUnicodeStringToOemString(
|
|
PANSI_STRING oem,
|
|
PUNICODE_STRING uni,
|
|
BOOLEAN doalloc)
|
|
{
|
|
int len = uni->Length/sizeof(WCHAR);
|
|
|
|
TRACE("%p %s %i\n", oem, debugstr_us(uni), doalloc);
|
|
|
|
oem->Length = len;
|
|
if (doalloc)
|
|
{
|
|
oem->Buffer = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len+1);
|
|
if (! oem->Buffer) return STATUS_NO_MEMORY;
|
|
oem->MaximumLength = len + 1;
|
|
}
|
|
else if (oem->MaximumLength <= len)
|
|
{
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
lstrcpynWtoA(oem->Buffer, uni->Buffer, len+1);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* RtlUpcaseUnicodeStringToOemString
|
|
*
|
|
* NOTES
|
|
* writes terminating 0
|
|
*/
|
|
NTSTATUS
|
|
WINAPI RtlUpcaseUnicodeStringToOemString(
|
|
PANSI_STRING oem,
|
|
PUNICODE_STRING uni,
|
|
BOOLEAN doalloc)
|
|
{
|
|
int i, len = uni->Length/sizeof(WCHAR);
|
|
|
|
TRACE("%p %s %i\n", oem, debugstr_us(uni), doalloc);
|
|
|
|
oem->Length = len;
|
|
if (doalloc)
|
|
{
|
|
oem->Buffer = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len+1);
|
|
if (! oem->Buffer) return STATUS_NO_MEMORY;
|
|
oem->MaximumLength = len + 1;
|
|
}
|
|
else if (oem->MaximumLength <= len)
|
|
{
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
for (i=0; i < len; i++)
|
|
{
|
|
oem->Buffer[i] = NTDLL_towupper((char)(uni->Buffer[i]));
|
|
}
|
|
oem->Buffer[i] = 0;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* RtlUnicodeStringToAnsiString
|
|
*
|
|
* NOTES
|
|
* writes terminating 0
|
|
* copys a part if the buffer is to small
|
|
*/
|
|
NTSTATUS
|
|
WINAPI RtlUnicodeStringToAnsiString(
|
|
PANSI_STRING ansi,
|
|
PUNICODE_STRING uni,
|
|
BOOLEAN doalloc)
|
|
{
|
|
int len = uni->Length/sizeof(WCHAR);
|
|
NTSTATUS ret = STATUS_SUCCESS;
|
|
|
|
TRACE("%p %s %i\n", ansi, debugstr_us(uni), doalloc);
|
|
|
|
ansi->Length = len;
|
|
if (doalloc)
|
|
{
|
|
ansi->Buffer = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len+1);
|
|
if (! ansi->Buffer) return STATUS_NO_MEMORY;
|
|
ansi->MaximumLength = len + 1;
|
|
}
|
|
else if (ansi->MaximumLength <= len)
|
|
{
|
|
ansi->Length = ansi->MaximumLength - 1;
|
|
ret = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
lstrcpynWtoA(ansi->Buffer, uni->Buffer, ansi->Length+1);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
COPY BETWEEN ANSI/UNICODE_STRING AND MULTIBYTE STRINGS
|
|
*/
|
|
/**************************************************************************
|
|
* RtlMultiByteToUnicodeN
|
|
*
|
|
* NOTES
|
|
* dest can be equal to src
|
|
* if unistr is to small a part is copyed
|
|
*
|
|
* FIXME
|
|
* multibyte support
|
|
*/
|
|
NTSTATUS
|
|
WINAPI RtlMultiByteToUnicodeN(
|
|
LPWSTR unistr,
|
|
DWORD unilen,
|
|
LPDWORD reslen,
|
|
LPSTR oemstr,
|
|
DWORD oemlen)
|
|
{
|
|
UINT len;
|
|
int i;
|
|
|
|
TRACE("%p %lu, %p, %s, %lu\n", oemstr, oemlen, reslen, debugstr_w(unistr), unilen);
|
|
|
|
len = (unilen/sizeof(WCHAR) < oemlen) ? unilen/sizeof(WCHAR) : oemlen;
|
|
|
|
for (i = len-1; i>=0; i--)
|
|
unistr[i] = (WCHAR)oemstr[i];
|
|
|
|
if (reslen) *reslen = len * 2;
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* RtlOemToUnicodeN
|
|
*/
|
|
NTSTATUS
|
|
WINAPI RtlOemToUnicodeN(
|
|
LPWSTR unistr,
|
|
DWORD unilen,
|
|
LPDWORD reslen,
|
|
LPSTR oemstr,
|
|
DWORD oemlen)
|
|
{
|
|
UINT len;
|
|
int i;
|
|
|
|
TRACE("%p %lu, %p, %s, %lu\n", oemstr, oemlen, reslen, debugstr_w(unistr), unilen);
|
|
|
|
len = (unilen/sizeof(WCHAR) < oemlen) ? unilen/sizeof(WCHAR) : oemlen;
|
|
|
|
for (i = len-1; i>=0; i--)
|
|
unistr[i] = (WCHAR)oemstr[i];
|
|
|
|
if (reslen) *reslen = len * 2;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
* RtlUnicodeToOemN
|
|
*/
|
|
NTSTATUS
|
|
WINAPI RtlUnicodeToOemN(
|
|
LPSTR oemstr,
|
|
DWORD oemlen,
|
|
LPDWORD reslen,
|
|
LPWSTR unistr,
|
|
DWORD unilen)
|
|
{
|
|
UINT len;
|
|
int i;
|
|
|
|
TRACE("%p %lu, %p, %s, %lu\n", oemstr, oemlen, reslen, debugstr_w(unistr), unilen);
|
|
|
|
len = (oemlen < unilen/sizeof(WCHAR)) ? unilen/sizeof(WCHAR) : oemlen;
|
|
|
|
for (i = len-1; i>=0; i--)
|
|
oemstr[i] = (CHAR)unistr[i];
|
|
|
|
if (reslen) *reslen = len * 2;
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* RtlUpcaseUnicodeToOemN
|
|
*/
|
|
NTSTATUS
|
|
WINAPI RtlUpcaseUnicodeToOemN(
|
|
LPSTR oemstr,
|
|
DWORD oemlen,
|
|
LPDWORD reslen,
|
|
LPWSTR unistr,
|
|
DWORD unilen)
|
|
{
|
|
UINT len;
|
|
int i;
|
|
|
|
TRACE("%p %lu, %p, %s, %lu\n", oemstr, oemlen, reslen, debugstr_w(unistr), unilen);
|
|
|
|
len = (oemlen < unilen/sizeof(WCHAR)) ? unilen/sizeof(WCHAR) : oemlen;
|
|
|
|
for (i = len-1; i>=0; i--)
|
|
oemstr[i] = toupper((CHAR)unistr[i]);
|
|
|
|
if (reslen) *reslen = len * 2;
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* RtlUnicodeToMultiByteN
|
|
*/
|
|
NTSTATUS WINAPI RtlUnicodeToMultiByteN(
|
|
PCHAR MbString,
|
|
ULONG MbSize,
|
|
PULONG ResultSize,
|
|
PWCHAR UnicodeString,
|
|
ULONG UnicodeSize)
|
|
{
|
|
int Size = 0, i;
|
|
|
|
TRACE("(%p,%lu,%p,%p(%s),%lu)\n",
|
|
MbString, MbSize, ResultSize, UnicodeString, debugstr_w(UnicodeString), UnicodeSize);
|
|
|
|
Size = (UnicodeSize > (MbSize*sizeof(WCHAR))) ? MbSize: UnicodeSize/sizeof(WCHAR);
|
|
|
|
if (ResultSize != NULL) *ResultSize = Size;
|
|
|
|
for(i = 0; i < Size; i++)
|
|
{
|
|
*(MbString++) = *(UnicodeString++);
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
STRING SIZE
|
|
|
|
Rtlx* supports multibyte
|
|
*/
|
|
|
|
/**************************************************************************
|
|
* RtlxOemStringToUnicodeSize
|
|
*/
|
|
UINT WINAPI RtlxOemStringToUnicodeSize(PSTRING str)
|
|
{
|
|
return str->Length*2+2;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* RtlxAnsiStringToUnicodeSize
|
|
*/
|
|
UINT WINAPI RtlxAnsiStringToUnicodeSize(PANSI_STRING str)
|
|
{
|
|
return str->Length*2+2;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* RtlxUnicodeStringToOemSize
|
|
*
|
|
*/
|
|
UINT WINAPI RtlxUnicodeStringToOemSize(PUNICODE_STRING str)
|
|
{
|
|
return str->Length+1;
|
|
}
|
|
|
|
/*
|
|
MISC
|
|
*/
|
|
|
|
/**************************************************************************
|
|
* RtlIsTextUnicode
|
|
*
|
|
* Apply various feeble heuristics to guess whether
|
|
* the text buffer contains Unicode.
|
|
* FIXME: should implement more tests.
|
|
*/
|
|
DWORD WINAPI RtlIsTextUnicode(
|
|
LPVOID buf,
|
|
DWORD len,
|
|
DWORD *pf)
|
|
{
|
|
LPWSTR s = buf;
|
|
DWORD flags = -1, out_flags = 0;
|
|
|
|
if (!len)
|
|
goto out;
|
|
if (pf)
|
|
flags = *pf;
|
|
/*
|
|
* 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 (!(len & 1))
|
|
out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
|
|
|
|
/* Check for the special unicode marker byte. */
|
|
if (*s == 0xFEFF)
|
|
out_flags |= IS_TEXT_UNICODE_SIGNATURE;
|
|
|
|
/*
|
|
* Check whether the string passed all of the tests.
|
|
*/
|
|
flags &= ITU_IMPLEMENTED_TESTS;
|
|
if ((out_flags & flags) != flags)
|
|
len = 0;
|
|
out:
|
|
if (pf)
|
|
*pf = out_flags;
|
|
return len;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* RtlPrefixUnicodeString
|
|
*/
|
|
NTSTATUS WINAPI RtlPrefixUnicodeString(
|
|
PUNICODE_STRING a,
|
|
PUNICODE_STRING b,
|
|
DWORD x)
|
|
{
|
|
TRACE("(%s,%s,%lx)\n",debugstr_us(a),debugstr_us(b),x);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|