/*
 *  kexbases\ntdll\RtlString.c
 *
 *  Copyright (C) 2013, Ley0k
 *  Copyright (C) 2015-19 jumper
 *
 *  This file is part of KernelEx source code.
 *
 *  KernelEx 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; version 2 of the License.
 *
 *  KernelEx 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 GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* TODO:
 RtlUnicodeStringInit, RtlUnicodeStringInitEx,
 RtlpFreeMemory_new

  Ansi is single-byte
  Unicode is double-byte
  Oem currently assumes single-byte, but could be either depending upon default Windows language.

  Notes:
  ------
  *_STRING buffer lengths are always in bytes.
  *_STRING buffer text is not zero terminated.
  MultiByteToWideChar and WideCharToMultiByte lengths are in characters (not bytes)
    and only include the NULL terminator if -1 is given as input length.

 */


#include "ntstatus.h"
#include "common.h"
#include "_ntdll_apilist.h"
#include "..\advapi32\_advapi32_apilist.h"
//#include <limits.h>
typedef LONG NTSTATUS;

#undef  _WIN32_WINNT
#define _WIN32_WINDOWS 0x0410


/********** Byte-count wrappers for MultiByteToWideChar and WideCharToMultiByte *********/

int mb2wc (UINT cp, PCSTR pChar, ULONG cbChar, PWCH pWide, ULONG cbWide)
{ return 2 * MultiByteToWideChar (cp, 0, pChar, cbChar, pWide, cbWide/2); }

int s2us_size (UINT cp, PSTRING ps)
{ return 2 * MultiByteToWideChar (cp, 0, ps->Buffer, ps->Length, NULL, 0); }

// Convert STRING to UNICODE_STRING, returning bytes (not characters) written
int s2us (UINT cp, PSTRING psIn, PUNICODE_STRING pusOut) {
  return 2 * MultiByteToWideChar (cp, 0, psIn->Buffer,   psIn->Length,
                                         pusOut->Buffer, pusOut->MaximumLength/2);
}


// Convert UNICODE_STRING to STRING, returning bytes written (or needed if 
int wc2mb (UINT cp, PWCH pWide, ULONG cbWide, PCHAR pChar, ULONG cbChar)
{ return WideCharToMultiByte (cp, 0, pWide, cbWide/2, pChar, cbChar, 0, 0);
} // int wc2mb()

// For UNICODE_STRING to STRING conversion, return bytes needed
int us2s_size (UINT cp, PUNICODE_STRING pusIn)
{ return WideCharToMultiByte (cp, 0, pusIn->Buffer, pusIn->Length/2, NULL, 0, 0, 0);
} // int us2s_size()

// Convert UNICODE_STRING to STRING, returning bytes written
int us2s (UINT cp, PUNICODE_STRING pusIn, PSTRING psOut)
{ return WideCharToMultiByte (cp, 0, pusIn->Buffer, pusIn->Length/2,
                                     psOut->Buffer, psOut->Length,    0, 0 );
} // int us2s()


/********** Rtl*ToUnicodeSize *********
RtlAnsiStringToUnicodeSize  RtlxAnsiStringToUnicodeSize
RtlOemStringToUnicodeSize   RtlxOemStringToUnicodeSize
RtlMultiByteToUnicodeSize
***********/


/* MAKE_EXPORT RtlMultiByteToUnicodeSize_new=RtlMultiByteToUnicodeSize */

NTSTATUS RtlMultiByteToUnicodeSize_new (PULONG puSize, PCSTR pMbStr, ULONG cbMbSize)
{
  *puSize = mb2wc (CP_ACP, pMbStr, cbMbSize, NULL, 0);
  return STATUS_SUCCESS;
}


/* MAKE_EXPORT RtlAnsiStringToUnicodeSize_new=RtlAnsiStringToUnicodeSize */
/* MAKE_EXPORT RtlAnsiStringToUnicodeSize_new=RtlxAnsiStringToUnicodeSize */

DWORD RtlAnsiStringToUnicodeSize_new (PSTRING psIn)
{
  /* Return the size plus the null-char */
  return s2us_size (CP_ACP, psIn) + sizeof(WCHAR);
}


/* MAKE_EXPORT RtlOemStringToUnicodeSize_new=RtlOemStringToUnicodeSize */
/* MAKE_EXPORT RtlOemStringToUnicodeSize_new=RtlxOemStringToUnicodeSize */

DWORD RtlOemStringToUnicodeSize_new (PSTRING psIn)
{
  /* Return the size plus the null-char */
  return s2us_size (CP_OEMCP, psIn) + sizeof(WCHAR);
}



/********** RtlUnicode*To*Size *********
RtlUnicodeStringToAnsiSize  RtlxUnicodeStringToAnsiSize
RtlUnicodeStringToOemSize   RtlxUnicodeStringToOemSize
RtlUnicodeToMultiByteSize
***********/


/* MAKE_EXPORT RtlUnicodeToMultiByteSize_new=RtlUnicodeToMultiByteSize */

NTSTATUS RtlUnicodeToMultiByteSize_new (PULONG pMbSize, PWCH pWcStr, ULONG WcSize)
{
  /* *pMbSize = WideCharToMultiByte (CP_ACP, 0, pWcStr, WcSize/2, NULL, 0, NULL, NULL); */
  *pMbSize = wc2mb (CP_ACP, pWcStr, WcSize/2, NULL, 0);
  return STATUS_SUCCESS;
}



/* MAKE_EXPORT RtlUnicodeStringToASize_new=RtlUnicodeStringToAnsiSize */
/* MAKE_EXPORT RtlUnicodeStringToASize_new=RtlxUnicodeStringToAnsiSize */
/* MAKE_EXPORT RtlUnicodeStringToASize_new=RtlUnicodeStringToOemSize */
/* MAKE_EXPORT RtlUnicodeStringToASize_new=RtlxUnicodeStringToOemSize */

ULONG RtlUnicodeStringToASize_new (PUNICODE_STRING pusIn )
{
	ULONG uSize;

	RtlUnicodeToMultiByteSize_new (&uSize, pusIn->Buffer, pusIn->Length);

	return (uSize + sizeof(CHAR));
}



/********** Rtl*To*N *********/


/* MAKE_EXPORT RtlMultiByteToUnicodeN_new=RtlMultiByteToUnicodeN */

NTSTATUS RtlMultiByteToUnicodeN_new (
	PWCHAR  pWide,
	ULONG   cbWideMax,
	PULONG  pcbWide,
	PCSTR   pMbStr,
	ULONG   MbSize 
)
{
	*pcbWide = mb2wc (CP_ACP, pMbStr, MbSize, pWide, cbWideMax);
	return STATUS_SUCCESS;
}



/* MAKE_EXPORT RtlOemToUnicodeN_new=RtlOemToUnicodeN */

NTSTATUS RtlOemToUnicodeN_new(
	PWCHAR  pWide,
	ULONG   cbWideMax,
	PULONG  pcbWide,
	PCCH    pOem,
	ULONG   cbOem
)
{
	ULONG uSize;

	uSize = mb2wc (CP_OEMCP, pOem, cbOem, pWide, cbWideMax);

	if(uSize == 0)
		return STATUS_INVALID_PARAMETER;

	if(!IsBadWritePtr (pcbWide, sizeof(ULONG)))
		*pcbWide = uSize;

	return STATUS_SUCCESS;
}



/* MAKE_EXPORT RtlUnicodeToMultiByteN_new=RtlUnicodeToMultiByteN */

NTSTATUS RtlUnicodeToMultiByteN_new(
	PSTR    pMbStr,
	ULONG   MbMaxSize,
	PULONG  pMbSize,
	PWCH    pUnicodeStr,
	ULONG   UnicodeSize
)
{
	*pMbSize = WideCharToMultiByte (CP_ACP, 0, pUnicodeStr, UnicodeSize/2, pMbStr, MbMaxSize, NULL, NULL);

	return STATUS_SUCCESS;
}



/* ***FIX_EXPORT RtlUnicodeToOemN_new=RtlUnicodeToOemN */

NTSTATUS RtlUnicodeToOemN_new (
	PWCHAR  UnicodeString,
	ULONG   UnicodeSize,
	PULONG  ResultSize,
	PCCH    OemString,
	ULONG   OemSize
)
{
	ULONG uSize;

	uSize = WideCharToMultiByte (CP_OEMCP,
								0,
								UnicodeString,
								UnicodeSize/2,
								(LPSTR)OemString,
								OemSize,
								NULL,
								NULL);

	if (uSize == 0)
		return STATUS_INVALID_PARAMETER;

	if (!IsBadWritePtr(ResultSize, sizeof(ULONG)))
		*ResultSize = uSize;

	return STATUS_SUCCESS;
}



/********* Heap Allocation *********/

/* MAKE_EXPORT RtlpAllocateMemory_new=RtlpAllocateMemory */

PWCHAR RtlpAllocateMemory_new (UINT cbLen, UINT tag)
#define TAG_ASTR 1
#define TAG_OSTR 1
#define TAG_USTR 2
{
	return (PWCHAR)HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, cbLen+2); //zt
}

#define RtlpAllocateStringMemory RtlpAllocateMemory_new
#define RtlpFreeStringMemory RtlpFreeMemory_new


#define SetMaxLenW(ps) SetMaxLen((PSTRING)ps)
void SetMaxLen (PSTRING ps)
{
    int cbSize = HeapSize (GetProcessHeap(), 0, ps->Buffer);
    ps->MaximumLength = min (cbSize, 65535);
}


NTSTATUS DestStringPrep (PSTRING ps, int cbLen, BOOL bAllocate)
{
  if (IsBadWritePtr (ps, sizeof(STRING)))
    return STATUS_INVALID_PARAMETER_1;

  if (cbLen > 65535)
    return STATUS_INVALID_PARAMETER_2; //STATUS_NAME_TOO_LONG;
  
  if (bAllocate) {
	  ps->Buffer = (PSTR)HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, cbLen+2); //zt
		if (!ps->Buffer)
			return ps->Length= 0, ps->MaximumLength= 0, STATUS_NO_MEMORY;

    int cbSize = HeapSize (GetProcessHeap(), 0, ps->Buffer);
    ps->MaximumLength = cbSize<=65535? cbSize: 65535;
  }

  ps->Length = cbLen;
  return (ps->Length > ps->MaximumLength)? STATUS_BUFFER_TOO_SMALL: STATUS_SUCCESS;
  //return STATUS_SUCCESS;

  // sbo is warning. should truncate conversion! check this in caller function
  //return (ps->Length > ps->MaximumLength)? STATUS_BUFFER_OVERFLOW: STATUS_SUCCESS;
}


/* MAKE_EXPORT RtlAnsiStringToUnicodeString_fix=RtlAnsiStringToUnicodeString */

NTSTATUS RtlAnsiStringToUnicodeString_fix(
	PUNICODE_STRING pusOut,
	PSTRING         pasIn,
	BOOLEAN         bAllocate )
{
	int      cbOut  = s2us_size (CP_ACP, pasIn);
	NTSTATUS Status = DestStringPrep ((PSTRING)pusOut, cbOut, bAllocate);
  if (Status<0) return Status;
 
	cbOut  = s2us (CP_ACP, pasIn, pusOut);
  return cbOut? STATUS_SUCCESS: STATUS_UNSUCCESSFUL;
}


/* MAKE_EXPORT RtlOemStringToUnicodeString_new=RtlOemStringToUnicodeString */

NTSTATUS RtlOemStringToUnicodeString_new(
	PUNICODE_STRING pusOut,
	POEM_STRING     posIn,
	BOOLEAN         bAllocate )
{
	int      cbOut  = s2us_size (CP_OEMCP, posIn);
	NTSTATUS Status = DestStringPrep ((PSTRING)pusOut, cbOut, bAllocate);
  if (Status<0) return Status;
 
	cbOut  = s2us (CP_OEMCP, posIn, pusOut);
  return cbOut? STATUS_SUCCESS: STATUS_UNSUCCESSFUL;
}


/* MAKE_EXPORT RtlUnicodeStringToAnsiString_fix=RtlUnicodeStringToAnsiString */

NTSTATUS RtlUnicodeStringToAnsiString_fix (
	PANSI_STRING    pasOut,
	PUNICODE_STRING pusIn,
	BOOLEAN         bAllocate
)
{
	int      cbOut  = us2s_size (CP_ACP, pusIn);
	NTSTATUS Status = DestStringPrep      ((PSTRING)pasOut, cbOut, bAllocate);
  if (Status<0) return Status;
 
	cbOut  = us2s (CP_ACP, pusIn, pasOut);

  return STATUS_SUCCESS;
}


/* MAKE_EXPORT RtlUnicodeStringToOemString_new=RtlUnicodeStringToOemString */

NTSTATUS RtlUnicodeStringToOemString_new (
	POEM_STRING     posOut,
	PUNICODE_STRING pusIn,
	BOOLEAN         bAllocate
)
{
	int      cbOut  = us2s_size (CP_OEMCP, pusIn);
	NTSTATUS Status = DestStringPrep      ((PSTRING)posOut, cbOut, bAllocate);
  if (Status<0) return Status;
 
	cbOut  = us2s (CP_OEMCP, pusIn, posOut);

  return STATUS_SUCCESS;
}


/* MAKE_EXPORT RtlUpcaseUnicodeString_new=RtlUpcaseUnicodeString */

NTSTATUS RtlUpcaseUnicodeString_new(
	PUNICODE_STRING pusOut,
	PUNICODE_STRING pusIn,
	BOOLEAN bAllocate 
)
{
	NTSTATUS Status = DestStringPrep ((PSTRING)pusOut, pusIn->Length, bAllocate);
	ULONG i, j;

	j = pusIn->Length / sizeof(WCHAR);

	for (i = 0; i < j; i++)
		pusOut->Buffer[i] = RtlUpcaseUnicodeChar_new(pusIn->Buffer[i]);

	return STATUS_SUCCESS;
}


/********** RtlCreate*String *********

/* MAKE_EXPORT RtlCreateUnicodeString_new=RtlCreateUnicodeString */

BOOLEAN RtlCreateUnicodeString_new (
  PUNICODE_STRING pusOut,
  PCWSTR          wszIn)
{
  if (DestStringPrep ((PSTRING)pusOut, sizeof(WCHAR)*lstrlenW (wszIn), TRUE))
		return FALSE;

  RtlCopyMemory (pusOut->Buffer, wszIn, pusOut->Length);
  return TRUE;
}



/* MAKE_EXPORT RtlCreateUnicodeStringFromAsciiz_new=RtlCreateUnicodeStringFromAsciiz */

BOOLEAN RtlCreateUnicodeStringFromAsciiz_new(
  PUNICODE_STRING pusOut,
  PCSZ            szIn
) {
  ANSI_STRING     asIn;
  RtlInitString_new (&asIn, szIn);
  return RtlAnsiStringToUnicodeString_fix (pusOut, &asIn, TRUE)? FALSE: TRUE;
}




/* MAKE_EXPORT RtlCompareUnicodeString_new=RtlCompareUnicodeString */

LONG RtlCompareUnicodeString_new(
	IN PUNICODE_STRING String1,
	IN PUNICODE_STRING String2,
	IN BOOLEAN CaseInsensitive )
{
	UINT uLength;
	LONG result = 0;
	LPCWSTR p1, p2;

	uLength = min(String1->Length, String2->Length) / sizeof(WCHAR);
	p1 = String1->Buffer;
	p2 = String2->Buffer;

	if(CaseInsensitive)
	{
		while (!result && uLength--)
			result = towupper(*p1++) - towupper(*p2++);
	}
	else
	{
		while(!result && uLength--)
			result = *p1++ - *p2++;
	}

	if (!result)
		result = String1->Length - String2->Length;

	return result;
}


/* MAKE_EXPORT RtlEqualUnicodeString_new=RtlEqualUnicodeString */

BOOLEAN RtlEqualUnicodeString_new(
	IN CONST PUNICODE_STRING String1,
	IN CONST PUNICODE_STRING String2,
	IN BOOLEAN CaseInsensitive
)
{
	if (String1->Length != String2->Length)
		return FALSE;

    return !RtlCompareUnicodeString_new(String1, String2, CaseInsensitive);
}



/* MAKE_EXPORT RtlExpandEnvironmentStrings_U_new=RtlExpandEnvironmentStrings_U */

NTSTATUS RtlExpandEnvironmentStrings_U_new(
	IN PWSTR Environment,
	IN PUNICODE_STRING pusSource,
	OUT PUNICODE_STRING pusDestination,
	OUT PULONG Length
)
{
  STRING asSource, asDest;
  RtlUnicodeStringToAnsiString_fix (&asSource, pusSource, TRUE);
  UINT uLen = ExpandEnvironmentStringsA (asSource.Buffer, NULL, 0);
	NTSTATUS Status = DestStringPrep (&asDest, uLen, TRUE);
  uLen = ExpandEnvironmentStringsA (asSource.Buffer, asDest.Buffer, asDest.MaximumLength);

  DWORD dwLength;

	dwLength = 0;  /* FIXME: Kernel32.ExpandEnvironmentStringsW is a stub, should be:
  ExpandEnvironmentStringsW_new(Source->Buffer,
											Destination->Buffer,
											Destination->Length);
                      */

	if(dwLength == 0)
		return STATUS_INVALID_PARAMETER;

	*Length = dwLength;

	return STATUS_SUCCESS;
}



/* MAKE_EXPORT RtlFreeString_new=RtlFreeAnsiString    */
/* MAKE_EXPORT RtlFreeString_new=RtlFreeOemString     */
/* MAKE_EXPORT RtlFreeString_new=RtlFreeUnicodeString */

VOID RtlFreeString_new (PSTRING pString)
{
  if (!IsBadWritePtr (pString, sizeof(STRING))) {
		pString->Length = 0;
		pString->MaximumLength = 0;
    if (pString->Buffer) {
      HeapFree (GetProcessHeap(), 0, pString->Buffer);
      pString->Buffer = NULL;
    } // if Buffer
  } // if pString
} // RtlFreeString



/* MAKE_EXPORT RtlInitString_new=RtlInitAnsiString  */
/* MAKE_EXPORT RtlInitString_new=RtlInitOemString   */
/* MAKE_EXPORT RtlInitString_new=RtlInitString      */

VOID RtlInitString_new(
  IN OUT  PSTRING pString,
  IN      PCSZ    szSource
)
{
  pString->Length         = 0;
  pString->MaximumLength  = 0;
  pString->Buffer         = (PCHAR)szSource;
  if (szSource) {
    UINT uLength = lstrlenA (szSource);
    pString->Length        = (uLength> 0xFFFF) ? 0xFFFF : (WORD)uLength;
    pString->MaximumLength = (uLength>=0xFFFF) ? 0xFFFF : (WORD)uLength + 1;
  }
}



/* MAKE_EXPORT RtlInitStringEx_new=RtlInitAnsiStringEx  */
/* MAKE_EXPORT RtlInitStringEx_new=RtlInitOemStringEx   */
/* MAKE~EXPORT RtlInitStringEx_new=RtlInitStringEx      */ // Win10 drivers only

NTSTATUS RtlInitStringEx_new(
  IN OUT  PSTRING pString,
  IN      PCSZ    szSource
)
{
  if (szSource && (lstrlenA (szSource) > 0xFFFF))
    return STATUS_NAME_TOO_LONG;
  RtlInitString_new (pString, szSource);
  return STATUS_SUCCESS;
}



/* MAKE_EXPORT RtlInitUnicodeString_new=RtlInitUnicodeString */

VOID RtlInitUnicodeString_new(
  IN OUT  PUNICODE_STRING pString,
  IN      PWSTR           wszSource
)
{
  pString->Length         = 0;
  pString->MaximumLength  = 0;
  pString->Buffer         = wszSource;
  if (wszSource) {
    UINT uLength = lstrlenW (wszSource) * 2;
    pString->Length        = (uLength> 0xFFFE) ? 0xFFFE : (WORD)uLength;
    pString->MaximumLength = (uLength>=0xFFFE) ? 0xFFFE : (WORD)uLength + 2;
  }
}



/* MAKE_EXPORT RtlInitUnicodeStringEx_new=RtlInitUnicodeStringEx */

NTSTATUS RtlInitUnicodeStringEx_new(
  IN OUT  PUNICODE_STRING pString,
  IN      PWSTR           wszSource
)
{
  if (wszSource && (lstrlenW (wszSource) > 0x7FFF))
    return STATUS_NAME_TOO_LONG;
  RtlInitUnicodeString_new (pString, wszSource);
  return STATUS_SUCCESS;
}



/* MAKE_EXPORT RtlPrefixUnicodeString_new=RtlPrefixUnicodeString */

BOOLEAN RtlPrefixUnicodeString_new(
    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 (towupper(*pc1++) !=
					towupper(*pc2++))
					return FALSE;
			}
		}
		else
		{
			while(Length--)
			{
				if(*pc1++ != *pc2++)
					return FALSE;
			}
		}

		return TRUE;
	}

	return FALSE;
}



/* MAKE_EXPORT RtlUpcaseUnicodeChar_new=RtlUpcaseUnicodeChar */

WCHAR RtlUpcaseUnicodeChar_new (IN WCHAR Source)
{
	return towupper(Source);
}



/* MAKE_EXPORT RtlCopyUnicodeString_new=RtlCopyUnicodeString */

VOID RtlCopyUnicodeString_new (PUNICODE_STRING pusDest, PUNICODE_STRING pusSrc)
{
  pusDest->Length = !pusSrc? 0: min (pusDest->MaximumLength, pusSrc->Length);

  if (pusDest->Length > 0)
    RtlCopyMemory (pusDest->Buffer, pusSrc->Buffer, pusDest->Length);

  if (pusDest->Length + sizeof(UNICODE_NULL) <= pusDest->MaximumLength)
    pusDest->Buffer[pusDest->Length / sizeof(WCHAR)] = UNICODE_NULL;
}


/* MAKE_EXPORT RtlDuplicateUnicodeString_new=RtlDuplicateUnicodeString */

NTSTATUS RtlDuplicateUnicodeString_new (UINT Flags, PUNICODE_STRING pusSrc, PUNICODE_STRING pusDest)
{
  if ((Flags^1 > 2) || !pusDest || !pusSrc || 
      (!pusSrc->Buffer && pusSrc->MaximumLength) ||
      ( pusSrc->Length  > pusSrc->MaximumLength) )
    return STATUS_INVALID_PARAMETER;

  if ((pusSrc->Length == 0) && (Flags != 3)) {
      pusDest->Length = 0;
      pusDest->MaximumLength = 0;
      pusDest->Buffer = NULL;

  } else {
      pusDest->Buffer = RtlpAllocateStringMemory (pusSrc->Length, TAG_USTR);
      if (!pusDest->Buffer)
        return STATUS_NO_MEMORY;
      SetMaxLenW (pusDest);
      RtlCopyMemory (pusDest->Buffer, pusSrc->Buffer, pusSrc->Length);
      pusDest->Length = pusSrc->Length;
  }

  return STATUS_SUCCESS;
}


/* MAKE~EXPORT RtlDuplicateUnicodeString_new=RtlDuplicateUnicodeString *

NTSTATUS RtlUpcaseUnicodeToMultiByteN (PSTR AnsiDest->Buffer,
                                          AnsiDest->Length,
                                          &Index,
                                          UniSource->Buffer,
                                          UniSource->Length);
*/


// FILE: lib/rtl/encode.c
/* MAKE_EXPORT RtlRunDecodeUnicodeString_new=RtlRunDecodeUnicodeString */

VOID RtlRunDecodeUnicodeString_new (UCHAR hash, PUNICODE_STRING pus)
{
}


/* MAKE_EXPORT RtlRunEncodeUnicodeString_new=RtlRunEncodeUnicodeString */

VOID RtlRunEncodeUnicodeString_new (PUCHAR phash, PUNICODE_STRING pus)
{
}

