Blame src/argv/ntapi_tt_argv_envp.c

dd89bb
/********************************************************/
dd89bb
/*  ntapi: Native API core library                      */
dd89bb
/*  Copyright (C) 2013,2014,2015  Z. Gilboa             */
dd89bb
/*  Released under GPLv2 and GPLv3; see COPYING.NTAPI.  */
dd89bb
/********************************************************/
dd89bb
dd89bb
#include <psxtypes/psxtypes.h>
dd89bb
#include <pemagine/pemagine.h>
dd89bb
#include <ntapi/ntapi.h>
dd89bb
#include "ntapi_impl.h"
dd89bb
dd89bb
dd89bb
/**
dd89bb
 *  rules for parsing the process's command line arguments
dd89bb
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
dd89bb
 *
dd89bb
 *  delimiters:
dd89bb
 *  -----------
dd89bb
 *  + white space    (ascii 0x20)
dd89bb
 *  + horizontal tab (ascii 0x09)
dd89bb
 *
dd89bb
 *  quoted strings, and special characters
dd89bb
 *  --------------------------------------
dd89bb
 *  + delimiter characters within a quoted string ("string with white space",
dd89bb
 *    or string" with white "space), stand for their literal respective
dd89bb
 *    characters.
dd89bb
 *
dd89bb
 *  + a backslash followed by a double quote (\") stands for a literal
dd89bb
 *    double quote.
dd89bb
 *
dd89bb
 *  + unless followed by a double quote, a backslash is just a (literal)
dd89bb
 *    backslash.
dd89bb
 *
dd89bb
 *  + when followed by a double quotation mark, an even sequence of 2 or
dd89bb
 *    more backslashes (2n) should be interpreted as a sequence of n literal
dd89bb
 *    backslashes.  The double quotation mark then designates the start
dd89bb
 *    or end of a double quoted string.
dd89bb
 *
dd89bb
 *  + when followed by a double quotation mark, an odd sequence of 2 or
dd89bb
 *    more backslashes (2n+1) should be interpreted as a sequence of n
dd89bb
 *    literal backslashes, followed by a single literal double quote.
dd89bb
 *
dd89bb
 *  + if found within a double quoted string, a sequence of two double
dd89bb
 *    quotation marks should be interpreted as a single literal double
dd89bb
 *    quote.
dd89bb
 *
dd89bb
 *  +  balanced nesting of syntactic double quotes is permitted.
dd89bb
 *
dd89bb
**/
dd89bb
dd89bb
/* free-standing process runtime data */
dd89bb
static nt_runtime_data	__rtdata;
dd89bb
dd89bb
int32_t __stdcall __ntapi_tt_parse_cmd_line_args_utf16(
dd89bb
	__in	wchar16_t *	cmd_line,
dd89bb
	__out	int *		arg_count,
dd89bb
	__in	wchar16_t *	args_buffer,
dd89bb
	__in	size_t		args_buffer_len,
dd89bb
	__out	size_t *	args_bytes_written __optional,
dd89bb
	__in	wchar16_t **	argv_buffer,
dd89bb
	__in	size_t		argv_buffer_len,
dd89bb
	__in	uint32_t	arg_flags)
dd89bb
{
dd89bb
	/**
dd89bb
	  * parse the command line arguments pointed to by cmd_line,
dd89bb
	  * copy the parsed arguments to args_buffer,
dd89bb
	  * and return 0 upon success.
dd89bb
	  *
dd89bb
	  * cmd_line must be a valid pointer to a command line string,
dd89bb
	  * and args_buffer, argv_buffer, and arg_count should
dd89bb
	  * all be aligned; furthermore, args_buffer_len and
dd89bb
	  * and argv_buffer_len must be exact multiples of sizeof(size_t).
dd89bb
	  *
dd89bb
	  * In case of an error, report failure using the appropriate
dd89bb
	  * native status code.
dd89bb
	**/
dd89bb
dd89bb
	/**
dd89bb
	 *  UTF-16: no need to fully determine the code point of the
dd89bb
	 *  current character; all we need to do is validate the
dd89bb
	 *  character or surrogate pair, and set the value of
dd89bb
	 *  wch_next accordingly.
dd89bb
	**/
dd89bb
dd89bb
	#define HORIZONTAL_TAB	0x09
dd89bb
	#define WHITE_SPACE	0x20
dd89bb
	#define DOUBLE_QUOTE	0x22
dd89bb
	#define SINGLE_QUOTE	0x27
dd89bb
	#define BACKSLASH	0x5C
dd89bb
dd89bb
	#define IS_DELIMITER(x)	((x == HORIZONTAL_TAB) || (x == WHITE_SPACE))
dd89bb
dd89bb
	#define TEST_ARGS_BUFFER(nbytes) \
dd89bb
				if ((uintptr_t)arg + nbytes \
dd89bb
						> (uintptr_t)args_buffer + args_buffer_len) { \
dd89bb
					return NT_STATUS_BUFFER_TOO_SMALL; \
dd89bb
				}
dd89bb
dd89bb
	#define ADD_N_BACKSLASHES \
dd89bb
				TEST_ARGS_BUFFER(backslash_count * sizeof(wchar16_t)); \
dd89bb
				for (islash = 0; \
dd89bb
						islash < backslash_count; \
dd89bb
						islash++) { \
dd89bb
					*arg = BACKSLASH; \
dd89bb
					arg++; \
dd89bb
				} \
dd89bb
				backslash_count = 0;
dd89bb
dd89bb
	#define ADD_SINGLE_WCHAR16_t(x) \
dd89bb
				TEST_ARGS_BUFFER(sizeof(wchar16_t)); \
dd89bb
				*arg = x; \
dd89bb
				arg++;
dd89bb
dd89bb
	wchar16_t *	arg;		/* null-terminated, copied to buffer */
dd89bb
	wchar16_t **	parg;		/* next pointer in the argv array */
dd89bb
	wchar16_t *	wch;		/* character being processed */
dd89bb
	wchar16_t *	wch_next;
dd89bb
	unsigned int	backslash_count;
dd89bb
	unsigned int	islash;
dd89bb
	unsigned char	quoted_state;
dd89bb
dd89bb
	/* check parameters for validity and alignment */
dd89bb
	if ((!(uintptr_t)cmd_line) || (*cmd_line == 0))
dd89bb
		/* we require at least one argument */
dd89bb
		return NT_STATUS_INVALID_PARAMETER_1;
dd89bb
dd89bb
	else if (__NT_IS_MISALIGNED_BUFFER(args_buffer))
dd89bb
		return NT_STATUS_INVALID_PARAMETER_2;
dd89bb
dd89bb
	else if (__NT_IS_MISALIGNED_LENGTH(args_buffer_len))
dd89bb
		return NT_STATUS_INVALID_PARAMETER_3;
dd89bb
dd89bb
	else if (__NT_IS_MISALIGNED_BUFFER(argv_buffer))
dd89bb
		return NT_STATUS_INVALID_PARAMETER_5;
dd89bb
dd89bb
	else if (__NT_IS_MISALIGNED_LENGTH(argv_buffer_len))
dd89bb
		return NT_STATUS_INVALID_PARAMETER_6;
dd89bb
dd89bb
	else if (__NT_IS_MISALIGNED_BUFFER(arg_count))
dd89bb
		return NT_STATUS_INVALID_PARAMETER_7;
dd89bb
dd89bb
	/* zero-out the aligned buffers */
dd89bb
	__ntapi->tt_aligned_block_memset(args_buffer,0,args_buffer_len);
dd89bb
	__ntapi->tt_aligned_block_memset(argv_buffer,0,argv_buffer_len);
dd89bb
dd89bb
	/* initialize */
dd89bb
	wch		= cmd_line;
dd89bb
	arg		= args_buffer;
dd89bb
	parg		= argv_buffer;
dd89bb
	*parg		= arg;
dd89bb
	*arg_count	= 0;
dd89bb
	quoted_state	= 0;
dd89bb
	backslash_count	= 0;
dd89bb
dd89bb
	/* arg points to the first character of a command line argument */
dd89bb
	/* parg points to the next pointer in argv_buffer */
dd89bb
	while (*wch) {
dd89bb
		if (!(quoted_state) && (IS_DELIMITER(*wch))) {
dd89bb
			/* pending backslashes? */
dd89bb
			if (backslash_count)
dd89bb
				ADD_N_BACKSLASHES;
dd89bb
dd89bb
			/* reached a delimiter outside of a quoted string */
dd89bb
			/* argument: alignment and null-termination */
dd89bb
			arg = (wchar16_t *)((((uintptr_t)arg + sizeof(size_t))
dd89bb
					| (sizeof(size_t) - 1))
dd89bb
					^ (sizeof(size_t) - 1));
dd89bb
dd89bb
			/* skip this and remaining delimiters */
dd89bb
			wch_next = wch + 1;
dd89bb
			while ((*wch_next) && (IS_DELIMITER(*wch_next)))
dd89bb
				wch_next++;
dd89bb
dd89bb
			/* keep going? */
dd89bb
			if (*wch_next == 0) {
dd89bb
				/* no more characters to process */
dd89bb
				/* nothing to do */
dd89bb
			} else if ((uintptr_t)parg >= \
dd89bb
					(uintptr_t)argv_buffer \
dd89bb
					+ argv_buffer_len) {
dd89bb
				/* argv_buffer is too small */
dd89bb
				return NT_STATUS_BUFFER_TOO_SMALL;
dd89bb
			} else if ((uintptr_t)arg >= \
dd89bb
					(uintptr_t)args_buffer \
dd89bb
					+ args_buffer_len) {
dd89bb
				/* args_buffer is too small */
dd89bb
				return NT_STATUS_BUFFER_TOO_SMALL;
dd89bb
			} else {
dd89bb
				/* advance parg, set last member  */
dd89bb
				parg++;
dd89bb
				*parg = arg;
dd89bb
			}
dd89bb
		} else {
dd89bb
			/* the current character is not a delimiter... */
dd89bb
			/* determine wch_next */
188aac
			if ((*wch < 0xD800) || (*wch >= 0xE000)) {
dd89bb
				/* in the BMP, single 16-bit representation */
dd89bb
				wch_next = wch + 1;
dd89bb
			} else if ((*wch >= 0xD800) && (*wch < 0xDC00)) {
dd89bb
				/* validate surrogate pair */
dd89bb
				wch_next = wch + 1;
dd89bb
dd89bb
				if ((*wch_next >= 0xDC00) && (*wch_next < 0xE000))
dd89bb
					/* this is a valid surrogate pair */
dd89bb
					wch_next++;
dd89bb
				else
dd89bb
					return NT_STATUS_ILLEGAL_CHARACTER;
dd89bb
			} else
dd89bb
				return NT_STATUS_ILLEGAL_CHARACTER;
dd89bb
dd89bb
			/* we now know the position of this and the next character */
dd89bb
			/* continue with special cases */
dd89bb
dd89bb
			if (quoted_state && (*wch == DOUBLE_QUOTE) \
dd89bb
					&& (*wch_next == DOUBLE_QUOTE)) {
dd89bb
				/**
dd89bb
				 *  two consecutive double quotation marks
dd89bb
				 *  within a quoted string:
dd89bb
				 *  add a single quotation mark to the argument
dd89bb
				**/
dd89bb
				ADD_SINGLE_WCHAR16_t(DOUBLE_QUOTE);
dd89bb
				wch_next++;
dd89bb
			} else if (((backslash_count % 2) == 0) \
dd89bb
					&& (*wch == BACKSLASH) \
dd89bb
					&& (*wch_next == DOUBLE_QUOTE)) {
dd89bb
				/* 2n+1 backslashes followed by a double quote */
dd89bb
				backslash_count /= 2;
dd89bb
				/* add n backslashes */
dd89bb
				ADD_N_BACKSLASHES;
dd89bb
				/* add a literal double quotation mark */
dd89bb
				ADD_SINGLE_WCHAR16_t(DOUBLE_QUOTE);
dd89bb
				/* get ready for next character */
dd89bb
				wch_next++;
dd89bb
			} else if (backslash_count && (*wch == DOUBLE_QUOTE)) {
dd89bb
				/* 2n backslashes followed by a double quote */
dd89bb
				backslash_count /= 2;
dd89bb
				/* add n backslashes */
dd89bb
				ADD_N_BACKSLASHES;
dd89bb
				/* turn quoted_state on/off */
dd89bb
				quoted_state = !quoted_state;
dd89bb
			} else if ((*wch == BACKSLASH) \
dd89bb
						&& (*wch_next == BACKSLASH)) {
dd89bb
				/* this is a sequence of two backslashes */
dd89bb
				backslash_count += 2;
dd89bb
				wch_next++;
dd89bb
			} else {
dd89bb
				/* copy pending backslashes as needed */
dd89bb
				if (backslash_count)
dd89bb
					ADD_N_BACKSLASHES;
dd89bb
dd89bb
				if (*wch == DOUBLE_QUOTE) {
dd89bb
					/* turn quoted_state on/off */
dd89bb
					quoted_state = !quoted_state;
dd89bb
				} else {
dd89bb
					/* copy either two or four bytes */
dd89bb
					ADD_SINGLE_WCHAR16_t(*wch);
dd89bb
					wch++;
dd89bb
dd89bb
					/* surrogate pair? */
dd89bb
					if (wch < wch_next) {
dd89bb
						ADD_SINGLE_WCHAR16_t(*wch);
dd89bb
					}
dd89bb
				}
dd89bb
			}
dd89bb
		}
dd89bb
dd89bb
		/* proceed to the next character (or null termination) */
dd89bb
		wch = wch_next;
dd89bb
	}
dd89bb
dd89bb
	/* pending backslashes? */
dd89bb
	if (backslash_count)
dd89bb
		ADD_N_BACKSLASHES;
dd89bb
dd89bb
	/* null termination */
dd89bb
	ADD_SINGLE_WCHAR16_t(0);
dd89bb
dd89bb
	/* how many arguments did you say? */
dd89bb
	*arg_count = (int)(((uintptr_t)parg - (uintptr_t)argv_buffer)
dd89bb
				/ sizeof(size_t) + 1);
dd89bb
dd89bb
	/* output bytes written */
dd89bb
	if (args_bytes_written)
dd89bb
		*args_bytes_written = (uintptr_t)arg - (uintptr_t)args_buffer;
dd89bb
dd89bb
	return NT_STATUS_SUCCESS;
dd89bb
}
dd89bb
dd89bb
dd89bb
int32_t __stdcall __ntapi_tt_get_argv_envp_utf16(
dd89bb
	__out	int *		argc,
dd89bb
	__out	wchar16_t ***	wargv,
dd89bb
	__out	wchar16_t ***	wenvp,
dd89bb
	__in	uint32_t	flags,
dd89bb
	__in	void *		ext_params	__optional,
dd89bb
	__out	void *		reserved	__optional)
dd89bb
{
dd89bb
	nt_runtime_data *		rtdata;
dd89bb
	nt_argv_envp_block_info		main_params_internal;
dd89bb
	nt_argv_envp_block_info *	main_params;
dd89bb
	nt_get_argv_envp_ext_params *	__ext_params;
dd89bb
	ntapi_internals *		__internals;
dd89bb
dd89bb
	unsigned	idx;
dd89bb
	int32_t		status;
dd89bb
	uintptr_t	addr;
dd89bb
	intptr_t	offset;
dd89bb
	wchar16_t *	wch_s;
dd89bb
	wchar16_t *	wch_dst;
dd89bb
	wchar16_t **	wch_p;
dd89bb
	char **		ch_p;
dd89bb
	uintptr_t *	psrc;
dd89bb
	uintptr_t *	pdst;
dd89bb
	uintptr_t *	paligned;
dd89bb
	wchar16_t *	pboundary;
dd89bb
dd89bb
	/* init */
dd89bb
	__internals = __ntapi_internals();
dd89bb
dd89bb
	/* use internal buffer? */
dd89bb
	if (flags & NT_GET_ARGV_ENVP_USE_CALLER_BUFFER) {
dd89bb
		__ext_params = (nt_get_argv_envp_ext_params *)ext_params;
dd89bb
		main_params  = &(__ext_params->argv_envp_block_info);
dd89bb
	} else {
dd89bb
		/* pointers to internal/local structures */
dd89bb
		main_params = &main_params_internal;
dd89bb
dd89bb
		/* init */
dd89bb
		__ntapi->tt_aligned_block_memset(
dd89bb
			main_params,0,
dd89bb
			sizeof(*main_params));
dd89bb
dd89bb
		/* use internal buffer */
dd89bb
		main_params->cmd_line		 = __ntapi_tt_get_cmd_line_utf16();
dd89bb
		main_params->wargv_buffer	 = __internals->ntapi_img_sec_bss->argv_envp_array;
dd89bb
		main_params->wargv_buffer_len	 = __NT_BSS_ARGV_BUFFER_SIZE;
dd89bb
		main_params->argv_envp_ptr_total	 = (int)(main_params->wargv_buffer_len
dd89bb
							/ sizeof(uintptr_t));
dd89bb
		main_params->wargs_buffer	 = (wchar16_t *)&(__internals->ntapi_img_sec_bss->args_envs_buffer);
dd89bb
		main_params->wargs_buffer_len	 = __NT_BSS_ARGS_BUFFER_SIZE;
dd89bb
	}
dd89bb
dd89bb
	/* (__ntapi_parse_cmd_line_args_utf16 will zero-out both buffers) */
dd89bb
	status = __ntapi_tt_parse_cmd_line_args_utf16(
dd89bb
		main_params->cmd_line,
dd89bb
		&main_params->argc,
dd89bb
		main_params->wargs_buffer,
dd89bb
		main_params->wargs_buffer_len,
dd89bb
		&main_params->wargs_bytes_written,
dd89bb
		main_params->wargv_buffer,
dd89bb
		main_params->wargv_buffer_len,
dd89bb
		0);
dd89bb
dd89bb
	if (status) return status;
dd89bb
dd89bb
	/* argv[] needs a terminating null pointer */
dd89bb
	if (main_params->argc == main_params->argv_envp_ptr_total)
dd89bb
		return NT_STATUS_BUFFER_TOO_SMALL;
dd89bb
dd89bb
	/* set idx to the envp[0] array index */
dd89bb
	idx = main_params->argc + 1;
dd89bb
dd89bb
	/* set wenvp[] to its starting address */
dd89bb
	main_params->wenvp_buffer = &main_params->wargv_buffer[idx];
dd89bb
dd89bb
	/* update wargv_buffer_len and envp_buffer_len */
dd89bb
	main_params->wenvp_buffer_len = main_params->wargv_buffer_len
dd89bb
					- (idx * sizeof(uintptr_t));
dd89bb
dd89bb
	main_params->wargv_buffer_len = idx * sizeof(uintptr_t);
dd89bb
dd89bb
	/* align wenvs at pointer-size boundary */
dd89bb
	main_params->wargs_bytes_written += sizeof(uintptr_t) - 1;
dd89bb
	main_params->wargs_bytes_written /= sizeof(uintptr_t);
dd89bb
	main_params->wargs_bytes_written *= sizeof(uintptr_t);
dd89bb
dd89bb
	/* book-keeping */
dd89bb
	main_params->wenvs_buffer  = main_params->wargs_buffer
dd89bb
					+ main_params->wargs_bytes_written;
dd89bb
dd89bb
	main_params->wenvs_buffer_len = main_params->wargs_buffer_len 
dd89bb
					- main_params->wargs_bytes_written;
dd89bb
dd89bb
	main_params->wargs_buffer_len = main_params->wargs_bytes_written;
dd89bb
dd89bb
dd89bb
	/* peb environment block (read-only) */
dd89bb
	wch_s = __ntapi_tt_get_peb_env_block_utf16();
dd89bb
dd89bb
	if ((!wch_s) || (!*wch_s))
dd89bb
		return NT_STATUS_DLL_INIT_FAILED;
dd89bb
dd89bb
	/* populate the envp[] array */
dd89bb
	while ((*wch_s) && (idx < main_params->argv_envp_ptr_total)) {
dd89bb
		main_params->envc++;
dd89bb
		wch_p = &(main_params->wargv_buffer[idx]);
dd89bb
		*wch_p = wch_s;
dd89bb
dd89bb
		/* skip the rest of the environment variable */
dd89bb
		while (*++wch_s);
dd89bb
dd89bb
		/* advance to the next variable (or final null termination) */
dd89bb
		wch_s++;
dd89bb
		idx++;
dd89bb
	}
dd89bb
dd89bb
	/* envp[] needs a terminating null pointer */
dd89bb
	if ((*wch_s) && (idx = main_params->argv_envp_ptr_total))
dd89bb
		return NT_STATUS_BUFFER_TOO_SMALL;
dd89bb
dd89bb
	/* copy environment? */
dd89bb
	if (flags & NT_GET_ARGV_ENVP_COPY_ENVIRONMENT) {
dd89bb
		/* wch_s now points at the final null termination */
dd89bb
		main_params->wenvs_bytes_used =
dd89bb
				((uintptr_t)wch_s
dd89bb
				- (uintptr_t)(*main_params->wenvp_buffer));
dd89bb
dd89bb
		/* do we have enough room? */
dd89bb
		if (main_params->wenvs_buffer_len < main_params->wenvs_bytes_used)
dd89bb
			return NT_STATUS_BUFFER_TOO_SMALL;
dd89bb
dd89bb
		/* upper boundary */
dd89bb
		pboundary = ++wch_s;
dd89bb
dd89bb
		/* you'd expect the peb environment block to be aligned, 
dd89bb
		   but one can never know... */
dd89bb
		wch_s 	= *main_params->wenvp_buffer;
dd89bb
		wch_dst = main_params->wenvs_buffer;
dd89bb
dd89bb
		while ((uintptr_t)wch_s % sizeof(uintptr_t)) {
dd89bb
			*wch_dst = *wch_s;
dd89bb
			wch_s++;
dd89bb
			wch_dst++;
dd89bb
		}
dd89bb
dd89bb
		/* copy the aligned portion of the environment block */
dd89bb
		addr = (uintptr_t)(pboundary);
dd89bb
		addr /= sizeof(uintptr_t);
dd89bb
		addr *= sizeof(uintptr_t);
dd89bb
		paligned = (uintptr_t *)addr;
dd89bb
dd89bb
		psrc = (uintptr_t *)wch_s;
dd89bb
		pdst = (uintptr_t *)wch_dst;
dd89bb
dd89bb
		while (psrc < paligned) {
dd89bb
			*pdst = *psrc;
dd89bb
			psrc++;
dd89bb
			pdst++;
dd89bb
		}
dd89bb
dd89bb
		/* copy any remaining bytes */
dd89bb
		wch_s	= (wchar16_t *)paligned;
dd89bb
		wch_dst	= (wchar16_t *)pdst;
dd89bb
dd89bb
		while (wch_s < pboundary) {
dd89bb
			*wch_dst = *wch_s;
dd89bb
			wch_s++;
dd89bb
			wch_dst++;
dd89bb
		}
dd89bb
dd89bb
		/* finally, we update the envp[] pointers */
dd89bb
		offset = (intptr_t)main_params->wenvs_buffer
dd89bb
			- (intptr_t)*main_params->wenvp_buffer;
dd89bb
dd89bb
		wch_p = main_params->wenvp_buffer;
dd89bb
dd89bb
		while (*wch_p) {
dd89bb
			addr = ((uintptr_t)*wch_p) + offset;
dd89bb
			*wch_p = (wchar16_t *)addr;
dd89bb
			wch_p++;
dd89bb
		}
dd89bb
	}
dd89bb
dd89bb
	/* (command line arguments always get validated) */
dd89bb
	/* validate the environment block? */
dd89bb
	if (flags & NT_GET_ARGV_ENVP_VALIDATE_UTF16) {
dd89bb
		wch_p = main_params->wenvp_buffer;
dd89bb
dd89bb
		while (*wch_p) {
dd89bb
			status = __ntapi->uc_validate_unicode_stream_utf16(
dd89bb
				*wch_p,
dd89bb
				0,0,0,0,0);
dd89bb
dd89bb
			if (status != NT_STATUS_SUCCESS)
dd89bb
				return status;
dd89bb
			else
dd89bb
				wch_p++;
dd89bb
		}
dd89bb
	}
dd89bb
dd89bb
	/* once */
dd89bb
	if (!__internals->rtdata) {
dd89bb
		__ntapi->tt_get_runtime_data(
dd89bb
			&__internals->rtdata,
dd89bb
			main_params->wargv_buffer);
dd89bb
dd89bb
		if (!__internals->rtdata) {
dd89bb
			__internals->rtdata = &__rtdata;
dd89bb
dd89bb
			if ((status =__ntapi->tt_init_runtime_data(&__rtdata)))
dd89bb
				return status;
dd89bb
dd89bb
		} else if ((status =__ntapi->tt_update_runtime_data(__internals->rtdata)))
dd89bb
			return status;
dd89bb
dd89bb
		rtdata = __internals->rtdata;
dd89bb
dd89bb
		rtdata->peb_envc  = main_params->envc;
dd89bb
		rtdata->peb_argc	  = main_params->argc;
dd89bb
		rtdata->peb_wargv = main_params->wargv_buffer;
dd89bb
		rtdata->peb_wenvp = main_params->wenvp_buffer;
dd89bb
dd89bb
		/* integral wargv, wenvp, argv, envp */
dd89bb
		if (rtdata->wargv) {
dd89bb
			rtdata->wargv += (uintptr_t)rtdata / sizeof(wchar16_t *);
dd89bb
dd89bb
			for (wch_p=rtdata->wargv; *wch_p; wch_p++)
dd89bb
				*wch_p += (uintptr_t)rtdata / sizeof(wchar16_t);
dd89bb
		};
dd89bb
dd89bb
		if (rtdata->wenvp) {
dd89bb
			rtdata->wenvp += (uintptr_t)rtdata / sizeof(wchar16_t *);
dd89bb
dd89bb
			for (wch_p=rtdata->wenvp; *wch_p; wch_p++)
dd89bb
				*wch_p += (uintptr_t)rtdata / sizeof(wchar16_t);
dd89bb
		}
dd89bb
dd89bb
		if (rtdata->argv) {
dd89bb
			rtdata->argv += (uintptr_t)rtdata / sizeof(char *);
dd89bb
dd89bb
			for (ch_p=rtdata->argv; *ch_p; ch_p++)
dd89bb
				*ch_p += (uintptr_t)rtdata;
dd89bb
dd89bb
			rtdata->argc = (int32_t)(ch_p - rtdata->argv);
dd89bb
		};
dd89bb
dd89bb
		if (rtdata->envp) {
dd89bb
			rtdata->envp += (uintptr_t)rtdata / sizeof(char *);
dd89bb
dd89bb
			for (ch_p=rtdata->envp; *ch_p; ch_p++)
dd89bb
				*ch_p += (uintptr_t)rtdata;
dd89bb
dd89bb
			rtdata->envc = (int32_t)(ch_p - rtdata->envp);
dd89bb
		};
dd89bb
	}
dd89bb
dd89bb
	/* we're good */
dd89bb
	*argc = main_params->argc;
dd89bb
	*wargv = main_params->wargv_buffer;
dd89bb
	*wenvp = main_params->wenvp_buffer;
dd89bb
dd89bb
	return NT_STATUS_SUCCESS;
dd89bb
}
dd89bb
dd89bb
dd89bb
int32_t __stdcall 	__ntapi_tt_get_argv_envp_utf8(
dd89bb
	__out	int *		argc,
dd89bb
	__out	char ***	argv,
dd89bb
	__out	char ***	envp,
dd89bb
	__in	uint32_t	flags,
dd89bb
	__in	void *		ext_params	__optional,
dd89bb
	__out	void *		reserved	__optional)
dd89bb
{
dd89bb
	int32_t			status;
dd89bb
	ntapi_internals *	__internals;
dd89bb
dd89bb
	wchar16_t **	wargv;
dd89bb
	wchar16_t **	wenvp;
dd89bb
	uint32_t	pcount;
dd89bb
dd89bb
	nt_get_argv_envp_ext_params	__ext_params_internal;
dd89bb
	nt_get_argv_envp_ext_params *	__ext_params;
dd89bb
	nt_argv_envp_block_info *	main_params;
dd89bb
dd89bb
	/* use internal buffer? */
dd89bb
	if (flags & NT_GET_ARGV_ENVP_USE_CALLER_BUFFER) {
dd89bb
		__ext_params = (nt_get_argv_envp_ext_params *)ext_params;
dd89bb
		main_params  = &__ext_params->argv_envp_block_info;
dd89bb
	} else {
dd89bb
		/* pointers to internal/local structures */
dd89bb
		__ext_params = &__ext_params_internal;
dd89bb
		main_params  = &__ext_params->argv_envp_block_info;
dd89bb
dd89bb
		/* init */
dd89bb
		__ntapi->tt_aligned_block_memset(
dd89bb
			main_params,0,
dd89bb
			sizeof(*main_params));
dd89bb
dd89bb
		__internals = __ntapi_internals();
dd89bb
dd89bb
		/* use internal buffer */
dd89bb
		main_params->cmd_line		 = __ntapi_tt_get_cmd_line_utf16();
dd89bb
		main_params->wargv_buffer	 = __internals->ntapi_img_sec_bss->argv_envp_array;
dd89bb
		main_params->wargv_buffer_len	 = __NT_BSS_ARGV_BUFFER_SIZE;
dd89bb
		main_params->argv_envp_ptr_total	 = (int)(main_params->wargv_buffer_len
dd89bb
							/ sizeof(uintptr_t));
dd89bb
		main_params->wargs_buffer	 = (wchar16_t *)&(__internals->ntapi_img_sec_bss->args_envs_buffer);
dd89bb
		main_params->wargs_buffer_len	 = __NT_BSS_ARGS_BUFFER_SIZE;
dd89bb
	}
dd89bb
dd89bb
	/* start with obtaining the utf-16 environment */
dd89bb
	status = __ntapi->tt_get_argv_envp_utf16(
dd89bb
		argc,
dd89bb
		&wargv,
dd89bb
		&wenvp,
dd89bb
		flags | NT_GET_ARGV_ENVP_USE_CALLER_BUFFER,
dd89bb
		__ext_params,
dd89bb
		reserved);
dd89bb
dd89bb
	if (status) return status;
dd89bb
dd89bb
	/* enough pointers left? */
dd89bb
	pcount = main_params->argc + 1 + main_params->envc + 1;
dd89bb
dd89bb
	if (pcount > (main_params->argv_envp_ptr_total / 2))
dd89bb
		return NT_STATUS_BUFFER_TOO_SMALL;
dd89bb
	else if ((main_params->wenvs_buffer_len - main_params->wenvs_bytes_used)
dd89bb
			< sizeof(uintptr_t))
dd89bb
		return NT_STATUS_BUFFER_TOO_SMALL;
dd89bb
dd89bb
	/* first args byte should be aligned at pointer-size boundary */
dd89bb
	main_params->wenvs_bytes_used += sizeof(uintptr_t) - 1;
dd89bb
	main_params->wenvs_bytes_used /= sizeof(uintptr_t);
dd89bb
	main_params->wenvs_bytes_used *= sizeof(uintptr_t);
dd89bb
dd89bb
	/* book-keeping */
dd89bb
	/* block reminder: wargs -- wenvs -- args -- envs */
dd89bb
	main_params->argv = (char **)main_params->wenvp_buffer;
dd89bb
	main_params->argv += main_params->envc + 1;
dd89bb
dd89bb
	main_params->args_buffer = (char *)main_params->wenvs_buffer;
dd89bb
	main_params->args_buffer += main_params->wenvs_bytes_used;
dd89bb
dd89bb
	main_params->args_buffer_len = main_params->wenvs_buffer_len
dd89bb
					- main_params->wenvs_bytes_used;
dd89bb
dd89bb
	main_params->wenvs_buffer_len = main_params->wenvs_bytes_used;
dd89bb
dd89bb
	/* create a utf-8 argv[] array */
dd89bb
	status = __ntapi_tt_array_convert_utf16_to_utf8(
dd89bb
		main_params->wargv_buffer,
dd89bb
		main_params->argv,
dd89bb
		0,
dd89bb
		main_params->args_buffer,
dd89bb
		main_params->args_buffer_len,
dd89bb
		&main_params->args_bytes_written);
dd89bb
dd89bb
	if (status) return status;
dd89bb
dd89bb
	/* first envs byte should be aligned to pointer-size boundary */
dd89bb
	main_params->args_bytes_written += sizeof(uintptr_t) - 1;
dd89bb
	main_params->args_bytes_written /= sizeof(uintptr_t);
dd89bb
	main_params->args_bytes_written *= sizeof(uintptr_t);
dd89bb
dd89bb
	/* book-keeping */
dd89bb
	main_params->envp = main_params->argv + main_params->argc + 1;
dd89bb
dd89bb
	main_params->envs_buffer  = main_params->args_buffer
dd89bb
					+ main_params->args_bytes_written;
dd89bb
dd89bb
	main_params->envs_buffer_len = main_params->args_buffer_len 
dd89bb
					- main_params->args_bytes_written;
dd89bb
dd89bb
	main_params->args_buffer_len = main_params->args_bytes_written;
dd89bb
dd89bb
	/* subsequent streams (if any) should be aligned to pointer-size boundary */
dd89bb
	main_params->envs_bytes_used += sizeof(uintptr_t) - 1;
dd89bb
	main_params->envs_bytes_used /= sizeof(uintptr_t);
dd89bb
	main_params->envs_bytes_used *= sizeof(uintptr_t);
dd89bb
dd89bb
	/* create a utf-8 envp[] array */
dd89bb
	status = __ntapi_tt_array_convert_utf16_to_utf8(
dd89bb
		main_params->wenvp_buffer,
dd89bb
		main_params->envp,
dd89bb
		0,
dd89bb
		main_params->envs_buffer,
dd89bb
		main_params->envs_buffer_len,
dd89bb
		&main_params->envs_bytes_used);
dd89bb
dd89bb
	if (status) return status;
dd89bb
dd89bb
	/* we're good */
dd89bb
	*argc = main_params->argc;
dd89bb
	*argv = main_params->argv;
dd89bb
	*envp = main_params->envp;
dd89bb
dd89bb
	return NT_STATUS_SUCCESS;
dd89bb
}
dd89bb
dd89bb
dd89bb
wchar16_t * __stdcall __ntapi_tt_get_cmd_line_utf16(void)
dd89bb
{
dd89bb
	nt_peb *		peb;
dd89bb
	nt_unicode_string	cmd_line;
dd89bb
dd89bb
	peb = (nt_peb *)pe_get_peb_address();
dd89bb
dd89bb
	if (peb) {
dd89bb
		cmd_line = peb->process_params->command_line;
dd89bb
		return cmd_line.buffer;
dd89bb
	} else
dd89bb
		return (wchar16_t *)0;
dd89bb
}
dd89bb
dd89bb
dd89bb
wchar16_t * __stdcall __ntapi_tt_get_peb_env_block_utf16(void)
dd89bb
{
dd89bb
	nt_peb *		peb;
dd89bb
dd89bb
	peb = (nt_peb *)pe_get_peb_address();
dd89bb
dd89bb
	if (peb)
dd89bb
		return peb->process_params->environment;
dd89bb
	else
dd89bb
		return (wchar16_t *)0;
dd89bb
}