/*++
*******************************************************************************
* copyright (c) 1990-98 Digi International Inc., All Rights Reserved				*
* 																										*
* This software contains proprietary and confidential information of Digi		*
* International Inc.  By accepting transfer of this copy, Recipient agrees		*
* to retain this software in confidence, to prevent disclosure to others,		*
* and to make no use of this software other than that for which it was			*
* delivered.  This is an unpublished copyrighted work of Digi International	*
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly	*
* prohibited.																						*
* 																										*
* Restricted Rights Legend																		*
*																										*
* Use, duplication, or disclosure by the Government is subject to					*
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in			*
* Technical Data and Computer Software clause at DFARS 252.227-7031 or			*
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -				*
* Restricted Rights at 48 CFR 52.227-19, as applicable.								*
*																										*
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343				*
*																										*
*******************************************************************************

Module Name:

   digistring.c

Abstract:

   Misc kernelmode string handling routines.

Author:

   Michael Zarns

--*/

#include "digilib.h"


BOOLEAN 
DigiStrExtractMultiSzEntry(
	OUT PUNICODE_STRING pString, 
	IN PUNICODE_STRING  pMultiSz, 
	IN ULONG            Index )
/*++

Description:

	Build a unicode string struct pointing to the nth string in the source 
	multi-string.  Return FALSE if n < number of strings in the multistring.

Parameters:

	pString
		Output string if it was found

	pMultiSz
		Points to source multistring

	Index
		Index into the multistring of the string to return

Return Value:

	TRUE if string was found and pString was initialized.  Otherwise FALSE.

--*/
{
	BOOLEAN fSuccess;
	ULONG i, j;
	WCHAR const * const pwstr = pMultiSz->Buffer;
	ULONG const cch = pMultiSz->Length / sizeof(WCHAR);

	for ( i = j = 0; i < Index; i++ )
	{
		// Skip over one string
		while ( j < cch && pwstr[j] != UNICODE_NULL )
		{
			j++;
		}

		j++;  // Skip over null
	}

	if ( j < cch && pwstr[j] != UNICODE_NULL )
	{
		RtlInitUnicodeString( pString, &pwstr[j] );
		fSuccess = TRUE;
	}
	else
		fSuccess = FALSE;

	return fSuccess;
}

/*NTSTATUS
DigiStrAllocEmptyUnicodeString( 
	OUT PUNICODE_STRING		pUnicode,
	IN  ULONG	    		length )
++

Description:

	Alloc and init buffer for an empty unicode string.  Accepts pointer to 
	unicode structure, and the max length that the string can be.

Parameters:

	pUnicode
		Points to unicode string variable to initialize.

	length
		max length of the new unicode string allocation


Return Value:

	STATUS_SUCCESS, 
		or STATUS_RESOURCES if not alloc'd,
		or STATUS_INVALID_PARAMETER if bad param.
--
{
	NTSTATUS	Status = STATUS_SUCCESS;

	if ( pUnicode == NULL )
		return STATUS_INVALID_PARAMETER_1;
	if ( length > 256 )                       // This is arbitray number that I don't know if is right
		return STATUS_INVALID_PARAMETER_2;

	RtlInitUnicodeString( pUnicode, NULL );
	pUnicode->MaximumLength = sizeof( WCHAR ) * length;
	pUnicode->Buffer = ExAllocatePool( PagedPool, pUnicode->MaximumLength + 1 );
	if ( !pUnicode->Buffer )
	{
		Status = STATUS_INSUFFICIENT_RESOURCES;
		DigiDump( DEBUG_ERROR, ( "DigiStr: Could not allocate unicode string buffer!\n" ) );
		RtlZeroMemory( pUnicode, sizeof *pUnicode );
		return Status;
	}
	RtlZeroMemory( pUnicode->Buffer, pUnicode->MaximumLength );
	return Status;
}*/

NTSTATUS
DigiStrAllocUnicodeString( 
	OUT PUNICODE_STRING pUnicode,
	IN PCWSTR           pString1,
	IN PCWSTR           pString2 OPTIONAL,
	IN PCWSTR           pString3 OPTIONAL )
/*++

Description:

	Alloc and init buffer for unicode string.  Accepts up to three input strings to
	concatenate in the buffer.

Parameters:

	pUnicode
		Points to unicode string variable to initialize.

	pString1
		Required WSTR to be copied into new unicode string.

	pString2, pString3
		Optional WSTR to be concatenated to new unicode string.  May be NULL if not 
		needed.

Return Value:

	STATUS_SUCCESS, 
		or STATUS_RESOURCES if not alloc'd,
		or STATUS_INVALID_PARAMETER if bad param,
		or STATUS_BUFFER_TOO_SMALL if RtlAppendUnicodeToString failed.
--*/
{
	NTSTATUS Status;
	UNICODE_STRING String1, String2, String3;

	if ( pUnicode == NULL )
		return STATUS_INVALID_PARAMETER_1;

	if ( pString1 == NULL )
		return STATUS_INVALID_PARAMETER_2;

	RtlZeroMemory( pUnicode, sizeof *pUnicode );

	RtlInitUnicodeString( &String1, pString1 );
	RtlInitUnicodeString( &String2, pString2 );
	RtlInitUnicodeString( &String3, pString3 );

	pUnicode->Length = 0;
	pUnicode->MaximumLength = String1.Length + String2.Length + String3.Length + sizeof ( WCHAR );
	pUnicode->Buffer = DigiAllocMem( NonPagedPool, pUnicode->MaximumLength );
	
	if ( pUnicode->Buffer == NULL )
	{
		Status = STATUS_INSUFFICIENT_RESOURCES;
		DigiDump( DEBUG_ERROR, ( "DigiStr: Could not allocate unicode string buffer!\n" ) );
		RtlZeroMemory( pUnicode, sizeof *pUnicode );
		return Status;
	}

	pUnicode->Buffer[pUnicode->MaximumLength/sizeof(WCHAR)-1] = 0;	// NULL Terminate

	if ( String1.Length != 0 )
		(void)RtlAppendUnicodeStringToString( pUnicode, &String1 );

	if ( String2.Length != 0 )
		(void)RtlAppendUnicodeStringToString( pUnicode, &String2 );

	if ( String3.Length != 0 )
		(void)RtlAppendUnicodeStringToString( pUnicode, &String3 );

	Status = STATUS_SUCCESS;

	return Status;
}


VOID
DigiStrFreeUnicodeString( 
	IN PUNICODE_STRING pUnicode )
/*++

Description:

	Free the buffer for a unicode string previously allocated by 
	DigiStrAllocUnicodeString.

Parameters:

	PUNICODE_STRING pUnicode
		Points to unicode string to free.

Return Value:

	None

--*/
{
	ASSERT( pUnicode->Buffer );
	if ( pUnicode->Buffer )
		DigiFreeMem( pUnicode->Buffer );
	RtlInitUnicodeString( pUnicode, NULL );
}


// Path or root for creating Symbolic link names
#define DIGI_DEVICENAME_ROOT			L"\\Device\\"
#define DIGI_SYMBOLICNAME_ROOT		L"\\DosDevices\\"


NTSTATUS
DigiStrDeviceName( 
	OUT PUNICODE_STRING pDeviceName,
	IN PCWSTR           pName )
/*++

Description:

	Alloc a new string that is the fully qualified device object name to be used in 
	calls to IoCreateDevice, given the desired devicename.  

Parameters:

	pDeviceName
		Output string containing "\\Device\\MyDevice", if successful.  This string must
		be freed using DigiStrFreeUnicodeString.

	pName
		Actual devicename, typically something like "DigiSxb3".

Return Value:

	STATUS_SUCCESS if successful.

--*/
{
	return DigiStrAllocUnicodeString( pDeviceName, DIGI_DEVICENAME_ROOT, pName, NULL );
}


NTSTATUS
DigiStrSymbolicName( 
	OUT PUNICODE_STRING pSymbolicName,
	IN PCWSTR           pName )
/*++

Description:

	Alloc a new string that is the full symbolic linkname to be used in calls to 
	IoCreateSymbolicLink.

Parameters:

	pDeviceName
		Output string containing "\\DosDevices\\MyDevice", if successful.  This string must
		be freed using DigiStrFreeUnicodeString.

	pName
		Actual devicename, typically something like "DigiSxb3".

Return Value:

	STATUS_SUCCESS if successful.

--*/
{
	return DigiStrAllocUnicodeString( pSymbolicName, DIGI_SYMBOLICNAME_ROOT, pName, NULL );
}


