| |
| |
| |
| |
| |
| |
| #include <psxtypes/psxtypes.h> |
| #include <pemagine/pemagine.h> |
| #include <ntapi/ntapi.h> |
| #include "ntapi_impl.h" |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static nt_runtime_data __rtdata; |
| |
| int32_t __stdcall __ntapi_tt_parse_cmd_line_args_utf16( |
| __in wchar16_t * cmd_line, |
| __out int * arg_count, |
| __in wchar16_t * args_buffer, |
| __in size_t args_buffer_len, |
| __out size_t * args_bytes_written __optional, |
| __in wchar16_t ** argv_buffer, |
| __in size_t argv_buffer_len, |
| __in uint32_t arg_flags) |
| { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #define HORIZONTAL_TAB 0x09 |
| #define WHITE_SPACE 0x20 |
| #define DOUBLE_QUOTE 0x22 |
| #define SINGLE_QUOTE 0x27 |
| #define BACKSLASH 0x5C |
| |
| #define IS_DELIMITER(x) ((x == HORIZONTAL_TAB) || (x == WHITE_SPACE)) |
| |
| #define TEST_ARGS_BUFFER(nbytes) \ |
| if ((uintptr_t)arg + nbytes \ |
| > (uintptr_t)args_buffer + args_buffer_len) { \ |
| return NT_STATUS_BUFFER_TOO_SMALL; \ |
| } |
| |
| #define ADD_N_BACKSLASHES \ |
| TEST_ARGS_BUFFER(backslash_count * sizeof(wchar16_t)); \ |
| for (islash = 0; \ |
| islash < backslash_count; \ |
| islash++) { \ |
| *arg = BACKSLASH; \ |
| arg++; \ |
| } \ |
| backslash_count = 0; |
| |
| #define ADD_SINGLE_WCHAR16_t(x) \ |
| TEST_ARGS_BUFFER(sizeof(wchar16_t)); \ |
| *arg = x; \ |
| arg++; |
| |
| wchar16_t * arg; |
| wchar16_t ** parg; |
| wchar16_t * wch; |
| wchar16_t * wch_next; |
| unsigned int backslash_count; |
| unsigned int islash; |
| unsigned char quoted_state; |
| |
| |
| (void)arg_flags; |
| |
| |
| if ((!(uintptr_t)cmd_line) || (*cmd_line == 0)) |
| |
| return NT_STATUS_INVALID_PARAMETER_1; |
| |
| else if (__NT_IS_MISALIGNED_BUFFER(args_buffer)) |
| return NT_STATUS_INVALID_PARAMETER_2; |
| |
| else if (__NT_IS_MISALIGNED_LENGTH(args_buffer_len)) |
| return NT_STATUS_INVALID_PARAMETER_3; |
| |
| else if (__NT_IS_MISALIGNED_BUFFER(argv_buffer)) |
| return NT_STATUS_INVALID_PARAMETER_5; |
| |
| else if (__NT_IS_MISALIGNED_LENGTH(argv_buffer_len)) |
| return NT_STATUS_INVALID_PARAMETER_6; |
| |
| else if (__NT_IS_MISALIGNED_BUFFER(arg_count)) |
| return NT_STATUS_INVALID_PARAMETER_7; |
| |
| |
| __ntapi->tt_aligned_block_memset(args_buffer,0,args_buffer_len); |
| __ntapi->tt_aligned_block_memset(argv_buffer,0,argv_buffer_len); |
| |
| |
| wch = cmd_line; |
| arg = args_buffer; |
| parg = argv_buffer; |
| *parg = arg; |
| *arg_count = 0; |
| quoted_state = 0; |
| backslash_count = 0; |
| |
| |
| |
| while (*wch) { |
| if (!(quoted_state) && (IS_DELIMITER(*wch))) { |
| |
| if (backslash_count) |
| ADD_N_BACKSLASHES; |
| |
| |
| |
| arg = (wchar16_t *)((((uintptr_t)arg + sizeof(size_t)) |
| | (sizeof(size_t) - 1)) |
| ^ (sizeof(size_t) - 1)); |
| |
| |
| wch_next = wch + 1; |
| while ((*wch_next) && (IS_DELIMITER(*wch_next))) |
| wch_next++; |
| |
| |
| if (*wch_next == 0) { |
| |
| |
| } else if ((uintptr_t)parg >= \ |
| (uintptr_t)argv_buffer \ |
| + argv_buffer_len) { |
| |
| return NT_STATUS_BUFFER_TOO_SMALL; |
| } else if ((uintptr_t)arg >= \ |
| (uintptr_t)args_buffer \ |
| + args_buffer_len) { |
| |
| return NT_STATUS_BUFFER_TOO_SMALL; |
| } else { |
| |
| parg++; |
| *parg = arg; |
| } |
| } else { |
| |
| |
| if ((*wch < 0xD800) || (*wch >= 0xE000)) { |
| |
| wch_next = wch + 1; |
| } else if ((*wch >= 0xD800) && (*wch < 0xDC00)) { |
| |
| wch_next = wch + 1; |
| |
| if ((*wch_next >= 0xDC00) && (*wch_next < 0xE000)) |
| |
| wch_next++; |
| else |
| return NT_STATUS_ILLEGAL_CHARACTER; |
| } else |
| return NT_STATUS_ILLEGAL_CHARACTER; |
| |
| |
| |
| |
| if (quoted_state && (*wch == DOUBLE_QUOTE) \ |
| && (*wch_next == DOUBLE_QUOTE)) { |
| |
| |
| |
| |
| |
| ADD_SINGLE_WCHAR16_t(DOUBLE_QUOTE); |
| wch_next++; |
| } else if (((backslash_count % 2) == 0) \ |
| && (*wch == BACKSLASH) \ |
| && (*wch_next == DOUBLE_QUOTE)) { |
| |
| backslash_count /= 2; |
| |
| ADD_N_BACKSLASHES; |
| |
| ADD_SINGLE_WCHAR16_t(DOUBLE_QUOTE); |
| |
| wch_next++; |
| } else if (backslash_count && (*wch == DOUBLE_QUOTE)) { |
| |
| backslash_count /= 2; |
| |
| ADD_N_BACKSLASHES; |
| |
| quoted_state = !quoted_state; |
| } else if ((*wch == BACKSLASH) \ |
| && (*wch_next == BACKSLASH)) { |
| |
| backslash_count += 2; |
| wch_next++; |
| } else { |
| |
| if (backslash_count) |
| ADD_N_BACKSLASHES; |
| |
| if (*wch == DOUBLE_QUOTE) { |
| |
| quoted_state = !quoted_state; |
| } else { |
| |
| ADD_SINGLE_WCHAR16_t(*wch); |
| wch++; |
| |
| |
| if (wch < wch_next) { |
| ADD_SINGLE_WCHAR16_t(*wch); |
| } |
| } |
| } |
| } |
| |
| |
| wch = wch_next; |
| } |
| |
| |
| if (backslash_count) |
| ADD_N_BACKSLASHES; |
| |
| |
| ADD_SINGLE_WCHAR16_t(0); |
| |
| |
| *arg_count = (int)(((uintptr_t)parg - (uintptr_t)argv_buffer) |
| / sizeof(size_t) + 1); |
| |
| |
| if (args_bytes_written) |
| *args_bytes_written = (uintptr_t)arg - (uintptr_t)args_buffer; |
| |
| return NT_STATUS_SUCCESS; |
| } |
| |
| |
| int32_t __stdcall __ntapi_tt_get_argv_envp_utf16( |
| __out int * argc, |
| __out wchar16_t *** wargv, |
| __out wchar16_t *** wenvp, |
| __in uint32_t flags, |
| __in void * ext_params __optional, |
| __out void * reserved __optional) |
| { |
| nt_runtime_data * rtdata; |
| nt_argv_envp_block_info main_params_internal; |
| nt_argv_envp_block_info * main_params; |
| nt_get_argv_envp_ext_params * __ext_params; |
| ntapi_internals * __internals; |
| |
| unsigned idx; |
| int32_t status; |
| uintptr_t addr; |
| intptr_t offset; |
| wchar16_t * wch_s; |
| wchar16_t * wch_dst; |
| wchar16_t ** wch_p; |
| char ** ch_p; |
| uintptr_t * psrc; |
| uintptr_t * pdst; |
| uintptr_t * paligned; |
| wchar16_t * pboundary; |
| |
| |
| (void)reserved; |
| |
| |
| __internals = __ntapi_internals(); |
| |
| |
| if (flags & NT_GET_ARGV_ENVP_USE_CALLER_BUFFER) { |
| __ext_params = (nt_get_argv_envp_ext_params *)ext_params; |
| main_params = &(__ext_params->argv_envp_block_info); |
| } else { |
| |
| main_params = &main_params_internal; |
| |
| |
| __ntapi->tt_aligned_block_memset( |
| main_params,0, |
| sizeof(*main_params)); |
| |
| |
| main_params->cmd_line = __ntapi_tt_get_cmd_line_utf16(); |
| main_params->wargv_buffer = __internals->ntapi_img_sec_bss->argv_envp_array; |
| main_params->wargv_buffer_len = __NT_BSS_ARGV_BUFFER_SIZE; |
| main_params->argv_envp_ptr_total = (int)(main_params->wargv_buffer_len |
| / sizeof(uintptr_t)); |
| main_params->wargs_buffer = (wchar16_t *)&(__internals->ntapi_img_sec_bss->args_envs_buffer); |
| main_params->wargs_buffer_len = __NT_BSS_ARGS_BUFFER_SIZE; |
| } |
| |
| |
| status = __ntapi_tt_parse_cmd_line_args_utf16( |
| main_params->cmd_line, |
| &main_params->argc, |
| main_params->wargs_buffer, |
| main_params->wargs_buffer_len, |
| &main_params->wargs_bytes_written, |
| main_params->wargv_buffer, |
| main_params->wargv_buffer_len, |
| 0); |
| |
| if (status) return status; |
| |
| |
| if ((unsigned)main_params->argc == main_params->argv_envp_ptr_total) |
| return NT_STATUS_BUFFER_TOO_SMALL; |
| |
| |
| idx = main_params->argc + 1; |
| |
| |
| main_params->wenvp_buffer = &main_params->wargv_buffer[idx]; |
| |
| |
| main_params->wenvp_buffer_len = main_params->wargv_buffer_len |
| - (idx * sizeof(uintptr_t)); |
| |
| main_params->wargv_buffer_len = idx * sizeof(uintptr_t); |
| |
| |
| main_params->wargs_bytes_written += sizeof(uintptr_t) - 1; |
| main_params->wargs_bytes_written /= sizeof(uintptr_t); |
| main_params->wargs_bytes_written *= sizeof(uintptr_t); |
| |
| |
| main_params->wenvs_buffer = main_params->wargs_buffer |
| + main_params->wargs_bytes_written; |
| |
| main_params->wenvs_buffer_len = main_params->wargs_buffer_len |
| - main_params->wargs_bytes_written; |
| |
| main_params->wargs_buffer_len = main_params->wargs_bytes_written; |
| |
| |
| |
| wch_s = __ntapi_tt_get_peb_env_block_utf16(); |
| |
| if ((!wch_s) || (!*wch_s)) |
| return NT_STATUS_DLL_INIT_FAILED; |
| |
| |
| while ((*wch_s) && (idx < main_params->argv_envp_ptr_total)) { |
| main_params->envc++; |
| wch_p = &(main_params->wargv_buffer[idx]); |
| *wch_p = wch_s; |
| |
| |
| while (*++wch_s); |
| |
| |
| wch_s++; |
| idx++; |
| } |
| |
| |
| if ((*wch_s) && (idx = main_params->argv_envp_ptr_total)) |
| return NT_STATUS_BUFFER_TOO_SMALL; |
| |
| |
| if (flags & NT_GET_ARGV_ENVP_COPY_ENVIRONMENT) { |
| |
| main_params->wenvs_bytes_used = |
| ((uintptr_t)wch_s |
| - (uintptr_t)(*main_params->wenvp_buffer)); |
| |
| |
| if (main_params->wenvs_buffer_len < main_params->wenvs_bytes_used) |
| return NT_STATUS_BUFFER_TOO_SMALL; |
| |
| |
| pboundary = ++wch_s; |
| |
| |
| |
| wch_s = *main_params->wenvp_buffer; |
| wch_dst = main_params->wenvs_buffer; |
| |
| while ((uintptr_t)wch_s % sizeof(uintptr_t)) { |
| *wch_dst = *wch_s; |
| wch_s++; |
| wch_dst++; |
| } |
| |
| |
| addr = (uintptr_t)(pboundary); |
| addr /= sizeof(uintptr_t); |
| addr *= sizeof(uintptr_t); |
| paligned = (uintptr_t *)addr; |
| |
| psrc = (uintptr_t *)wch_s; |
| pdst = (uintptr_t *)wch_dst; |
| |
| while (psrc < paligned) { |
| *pdst = *psrc; |
| psrc++; |
| pdst++; |
| } |
| |
| |
| wch_s = (wchar16_t *)paligned; |
| wch_dst = (wchar16_t *)pdst; |
| |
| while (wch_s < pboundary) { |
| *wch_dst = *wch_s; |
| wch_s++; |
| wch_dst++; |
| } |
| |
| |
| offset = (intptr_t)main_params->wenvs_buffer |
| - (intptr_t)*main_params->wenvp_buffer; |
| |
| wch_p = main_params->wenvp_buffer; |
| |
| while (*wch_p) { |
| addr = ((uintptr_t)*wch_p) + offset; |
| *wch_p = (wchar16_t *)addr; |
| wch_p++; |
| } |
| } |
| |
| |
| |
| if (flags & NT_GET_ARGV_ENVP_VALIDATE_UTF16) { |
| wch_p = main_params->wenvp_buffer; |
| |
| while (*wch_p) { |
| status = __ntapi->uc_validate_unicode_stream_utf16( |
| *wch_p, |
| 0,0,0,0,0); |
| |
| if (status != NT_STATUS_SUCCESS) |
| return status; |
| else |
| wch_p++; |
| } |
| } |
| |
| |
| if (!__internals->rtdata) { |
| __ntapi->tt_get_runtime_data( |
| &__internals->rtdata, |
| main_params->wargv_buffer); |
| |
| if (!__internals->rtdata) { |
| __internals->rtdata = &__rtdata; |
| |
| if ((status =__ntapi->tt_init_runtime_data(&__rtdata))) |
| return status; |
| |
| } else if ((status =__ntapi->tt_update_runtime_data(__internals->rtdata))) |
| return status; |
| |
| rtdata = __internals->rtdata; |
| |
| rtdata->peb_envc = main_params->envc; |
| rtdata->peb_argc = main_params->argc; |
| rtdata->peb_wargv = main_params->wargv_buffer; |
| rtdata->peb_wenvp = main_params->wenvp_buffer; |
| |
| |
| if (rtdata->wargv) { |
| rtdata->wargv += (uintptr_t)rtdata / sizeof(wchar16_t *); |
| |
| for (wch_p=rtdata->wargv; *wch_p; wch_p++) |
| *wch_p += (uintptr_t)rtdata / sizeof(wchar16_t); |
| }; |
| |
| if (rtdata->wenvp) { |
| rtdata->wenvp += (uintptr_t)rtdata / sizeof(wchar16_t *); |
| |
| for (wch_p=rtdata->wenvp; *wch_p; wch_p++) |
| *wch_p += (uintptr_t)rtdata / sizeof(wchar16_t); |
| } |
| |
| if (rtdata->argv) { |
| rtdata->argv += (uintptr_t)rtdata / sizeof(char *); |
| |
| for (ch_p=rtdata->argv; *ch_p; ch_p++) |
| *ch_p += (uintptr_t)rtdata; |
| |
| rtdata->argc = (int32_t)(ch_p - rtdata->argv); |
| }; |
| |
| if (rtdata->envp) { |
| rtdata->envp += (uintptr_t)rtdata / sizeof(char *); |
| |
| for (ch_p=rtdata->envp; *ch_p; ch_p++) |
| *ch_p += (uintptr_t)rtdata; |
| |
| rtdata->envc = (int32_t)(ch_p - rtdata->envp); |
| }; |
| } |
| |
| |
| *argc = main_params->argc; |
| *wargv = main_params->wargv_buffer; |
| *wenvp = main_params->wenvp_buffer; |
| |
| return NT_STATUS_SUCCESS; |
| } |
| |
| |
| int32_t __stdcall __ntapi_tt_get_argv_envp_utf8( |
| __out int * argc, |
| __out char *** argv, |
| __out char *** envp, |
| __in uint32_t flags, |
| __in void * ext_params __optional, |
| __out void * reserved __optional) |
| { |
| int32_t status; |
| ntapi_internals * __internals; |
| |
| wchar16_t ** wargv; |
| wchar16_t ** wenvp; |
| uint32_t pcount; |
| |
| nt_get_argv_envp_ext_params __ext_params_internal; |
| nt_get_argv_envp_ext_params * __ext_params; |
| nt_argv_envp_block_info * main_params; |
| |
| |
| if (flags & NT_GET_ARGV_ENVP_USE_CALLER_BUFFER) { |
| __ext_params = (nt_get_argv_envp_ext_params *)ext_params; |
| main_params = &__ext_params->argv_envp_block_info; |
| } else { |
| |
| __ext_params = &__ext_params_internal; |
| main_params = &__ext_params->argv_envp_block_info; |
| |
| |
| __ntapi->tt_aligned_block_memset( |
| main_params,0, |
| sizeof(*main_params)); |
| |
| __internals = __ntapi_internals(); |
| |
| |
| main_params->cmd_line = __ntapi_tt_get_cmd_line_utf16(); |
| main_params->wargv_buffer = __internals->ntapi_img_sec_bss->argv_envp_array; |
| main_params->wargv_buffer_len = __NT_BSS_ARGV_BUFFER_SIZE; |
| main_params->argv_envp_ptr_total = (int)(main_params->wargv_buffer_len |
| / sizeof(uintptr_t)); |
| main_params->wargs_buffer = (wchar16_t *)&(__internals->ntapi_img_sec_bss->args_envs_buffer); |
| main_params->wargs_buffer_len = __NT_BSS_ARGS_BUFFER_SIZE; |
| } |
| |
| |
| status = __ntapi->tt_get_argv_envp_utf16( |
| argc, |
| &wargv, |
| &wenvp, |
| flags | NT_GET_ARGV_ENVP_USE_CALLER_BUFFER, |
| __ext_params, |
| reserved); |
| |
| if (status) return status; |
| |
| |
| pcount = main_params->argc + 1 + main_params->envc + 1; |
| |
| if (pcount > (main_params->argv_envp_ptr_total / 2)) |
| return NT_STATUS_BUFFER_TOO_SMALL; |
| else if ((main_params->wenvs_buffer_len - main_params->wenvs_bytes_used) |
| < sizeof(uintptr_t)) |
| return NT_STATUS_BUFFER_TOO_SMALL; |
| |
| |
| main_params->wenvs_bytes_used += sizeof(uintptr_t) - 1; |
| main_params->wenvs_bytes_used /= sizeof(uintptr_t); |
| main_params->wenvs_bytes_used *= sizeof(uintptr_t); |
| |
| |
| |
| main_params->argv = (char **)main_params->wenvp_buffer; |
| main_params->argv += main_params->envc + 1; |
| |
| main_params->args_buffer = (char *)main_params->wenvs_buffer; |
| main_params->args_buffer += main_params->wenvs_bytes_used; |
| |
| main_params->args_buffer_len = main_params->wenvs_buffer_len |
| - main_params->wenvs_bytes_used; |
| |
| main_params->wenvs_buffer_len = main_params->wenvs_bytes_used; |
| |
| |
| status = __ntapi_tt_array_convert_utf16_to_utf8( |
| main_params->wargv_buffer, |
| main_params->argv, |
| 0, |
| main_params->args_buffer, |
| main_params->args_buffer_len, |
| &main_params->args_bytes_written); |
| |
| if (status) return status; |
| |
| |
| main_params->args_bytes_written += sizeof(uintptr_t) - 1; |
| main_params->args_bytes_written /= sizeof(uintptr_t); |
| main_params->args_bytes_written *= sizeof(uintptr_t); |
| |
| |
| main_params->envp = main_params->argv + main_params->argc + 1; |
| |
| main_params->envs_buffer = main_params->args_buffer |
| + main_params->args_bytes_written; |
| |
| main_params->envs_buffer_len = main_params->args_buffer_len |
| - main_params->args_bytes_written; |
| |
| main_params->args_buffer_len = main_params->args_bytes_written; |
| |
| |
| main_params->envs_bytes_used += sizeof(uintptr_t) - 1; |
| main_params->envs_bytes_used /= sizeof(uintptr_t); |
| main_params->envs_bytes_used *= sizeof(uintptr_t); |
| |
| |
| status = __ntapi_tt_array_convert_utf16_to_utf8( |
| main_params->wenvp_buffer, |
| main_params->envp, |
| 0, |
| main_params->envs_buffer, |
| main_params->envs_buffer_len, |
| &main_params->envs_bytes_used); |
| |
| if (status) return status; |
| |
| |
| *argc = main_params->argc; |
| *argv = main_params->argv; |
| *envp = main_params->envp; |
| |
| return NT_STATUS_SUCCESS; |
| } |
| |
| |
| wchar16_t * __stdcall __ntapi_tt_get_cmd_line_utf16(void) |
| { |
| nt_peb * peb; |
| |
| return (peb = (nt_peb *)pe_get_peb_address()) |
| ? peb->process_params->command_line.buffer |
| : 0; |
| } |
| |
| |
| wchar16_t * __stdcall __ntapi_tt_get_peb_env_block_utf16(void) |
| { |
| nt_peb * peb; |
| |
| return (peb = (nt_peb *)pe_get_peb_address()) |
| ? peb->process_params->environment |
| : 0; |
| } |