|
|
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/nt_argv.h>
|
|
|
dd89bb |
#include <ntapi/ntapi.h>
|
|
|
dd89bb |
#include "ntapi_impl.h"
|
|
|
dd89bb |
|
|
|
dd89bb |
/**
|
|
|
dd89bb |
* scenario: program -e app [arg1 arg2 ... argn]
|
|
|
dd89bb |
* input: a utf-16 argument vector
|
|
|
dd89bb |
* output: a utf-16 cmd_line string
|
|
|
dd89bb |
* example: tty_pipe_create_child_process
|
|
|
dd89bb |
**/
|
|
|
dd89bb |
|
|
|
dd89bb |
int32_t __stdcall __ntapi_tt_array_copy_utf16(
|
|
|
dd89bb |
__out int * argc,
|
|
|
dd89bb |
__in const wchar16_t ** wargv,
|
|
|
dd89bb |
__in const wchar16_t ** wenvp,
|
|
|
dd89bb |
__in const wchar16_t * image_name __optional,
|
|
|
dd89bb |
__in const wchar16_t * interpreter __optional,
|
|
|
dd89bb |
__in const wchar16_t * optarg __optional,
|
|
|
dd89bb |
__in void * base,
|
|
|
dd89bb |
__out void * buffer,
|
|
|
dd89bb |
__in size_t buflen,
|
|
|
dd89bb |
__out size_t * blklen)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
const wchar16_t ** parg;
|
|
|
dd89bb |
const wchar16_t * warg;
|
|
|
dd89bb |
const wchar16_t * dummy;
|
|
|
dd89bb |
wchar16_t * wch;
|
|
|
dd89bb |
ptrdiff_t diff;
|
|
|
dd89bb |
ptrdiff_t ptrs;
|
|
|
dd89bb |
size_t needed;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* fallback */
|
|
|
dd89bb |
dummy = 0;
|
|
|
dd89bb |
wargv = wargv ? wargv : &dummy;
|
|
|
dd89bb |
wenvp = wenvp ? wenvp : &dummy;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* ptrs, needed */
|
|
|
dd89bb |
ptrs = 0;
|
|
|
dd89bb |
needed = 0;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (image_name) {
|
|
|
dd89bb |
ptrs++;
|
|
|
dd89bb |
needed += sizeof(wchar16_t *)
|
|
|
dd89bb |
+ __ntapi->tt_string_null_offset_short((const int16_t *)image_name)
|
|
|
dd89bb |
+ sizeof(wchar16_t);
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
for (parg=wargv; *parg; parg++)
|
|
|
dd89bb |
needed += sizeof(wchar16_t *)
|
|
|
dd89bb |
+ __ntapi->tt_string_null_offset_short((const int16_t *)*parg)
|
|
|
dd89bb |
+ sizeof(wchar16_t);
|
|
|
dd89bb |
|
|
|
dd89bb |
ptrs += (parg - wargv);
|
|
|
dd89bb |
*argc = (int)ptrs;
|
|
|
dd89bb |
|
|
|
dd89bb |
for (parg=wenvp; *parg; parg++)
|
|
|
dd89bb |
needed += sizeof(wchar16_t *)
|
|
|
dd89bb |
+ __ntapi->tt_string_null_offset_short((const int16_t *)*parg)
|
|
|
dd89bb |
+ sizeof(wchar16_t);
|
|
|
dd89bb |
|
|
|
dd89bb |
ptrs += (parg - wenvp);
|
|
|
dd89bb |
|
|
|
dd89bb |
ptrs += 2;
|
|
|
dd89bb |
needed += 2*sizeof(wchar16_t *);
|
|
|
dd89bb |
blklen = blklen ? blklen : &needed;
|
|
|
dd89bb |
*blklen = needed;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (buflen < needed)
|
|
|
dd89bb |
return NT_STATUS_BUFFER_TOO_SMALL;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* init */
|
|
|
dd89bb |
parg = (const wchar16_t **)buffer;
|
|
|
dd89bb |
wch = (wchar16_t *)(parg+ptrs);
|
|
|
dd89bb |
diff = (uintptr_t)base / sizeof(wchar16_t);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* image_name */
|
|
|
dd89bb |
if (image_name) {
|
|
|
dd89bb |
*parg++ = wch-diff;
|
|
|
dd89bb |
for (warg=image_name; *warg; warg++,wch++)
|
|
|
dd89bb |
*wch = *warg;
|
|
|
dd89bb |
*wch++ = '\0';
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* argv */
|
|
|
dd89bb |
for (; *wargv; wargv++) {
|
|
|
dd89bb |
*parg++=wch-diff;
|
|
|
dd89bb |
for (warg=*wargv; *warg; warg++,wch++)
|
|
|
dd89bb |
*wch = *warg;
|
|
|
dd89bb |
*wch++ = '\0';
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
*parg++ = 0;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* envp */
|
|
|
dd89bb |
for (; *wenvp; wenvp++) {
|
|
|
dd89bb |
*parg++=wch-diff;
|
|
|
dd89bb |
for (warg=*wenvp; *warg; warg++,wch++)
|
|
|
dd89bb |
*wch = *warg;
|
|
|
dd89bb |
*wch++ = '\0';
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
*parg++ = 0;
|
|
|
dd89bb |
|
|
|
dd89bb |
return NT_STATUS_SUCCESS;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
int32_t __stdcall __ntapi_tt_array_convert_utf16_to_utf8(
|
|
|
dd89bb |
__in wchar16_t ** warrv,
|
|
|
dd89bb |
__in char ** arrv,
|
|
|
dd89bb |
__in void * base,
|
|
|
dd89bb |
__in char * buffer,
|
|
|
dd89bb |
__in size_t buffer_len,
|
|
|
dd89bb |
__out size_t * bytes_written)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
uint8_t * ubound;
|
|
|
dd89bb |
uint8_t * ch;
|
|
|
dd89bb |
wchar16_t * wch;
|
|
|
dd89bb |
wchar16_t wx;
|
|
|
dd89bb |
wchar16_t wy;
|
|
|
dd89bb |
wchar16_t wz;
|
|
|
dd89bb |
wchar16_t wy_low;
|
|
|
dd89bb |
wchar16_t wy_high;
|
|
|
dd89bb |
wchar16_t ww;
|
|
|
dd89bb |
wchar16_t uuuuu;
|
|
|
dd89bb |
wchar16_t u_low;
|
|
|
dd89bb |
wchar16_t u_high;
|
|
|
dd89bb |
ptrdiff_t diff;
|
|
|
dd89bb |
|
|
|
dd89bb |
#define __UTF8_MAX_CODE_POINT_BYTES (4)
|
|
|
dd89bb |
|
|
|
dd89bb |
ch = (uint8_t *)buffer;
|
|
|
dd89bb |
ubound = (uint8_t *)buffer + buffer_len - __UTF8_MAX_CODE_POINT_BYTES;
|
|
|
dd89bb |
diff = (uintptr_t)base / sizeof(wchar16_t);
|
|
|
dd89bb |
|
|
|
dd89bb |
while (warrv && *warrv) {
|
|
|
dd89bb |
*arrv = (char *)(ch-(uintptr_t)base);
|
|
|
dd89bb |
wch = *warrv + diff;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* all utf-16 streams at stake have been validated */
|
|
|
dd89bb |
while (*wch && (ch < ubound)) {
|
|
|
dd89bb |
if (*wch <= 0x7F) {
|
|
|
dd89bb |
/* from: 00000000 0xxxxxxx (little endian) */
|
|
|
dd89bb |
/* to: 0xxxxxxx (utf-8) */
|
|
|
dd89bb |
*ch = (char)(*wch);
|
|
|
dd89bb |
} else if (*wch <= 0x7FF) {
|
|
|
dd89bb |
/* from: 00000yyy yyxxxxxx (little endian) */
|
|
|
dd89bb |
/* to: 110yyyyy 10xxxxxx (utf-8) */
|
|
|
dd89bb |
wy = *wch;
|
|
|
dd89bb |
wy >>= 6;
|
|
|
dd89bb |
|
|
|
dd89bb |
wx = *wch;
|
|
|
dd89bb |
wx <<= 10;
|
|
|
dd89bb |
wx >>= 10;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* write the y part */
|
|
|
dd89bb |
*ch = (char)(0xC0 | wy);
|
|
|
dd89bb |
ch++;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* write the x part */
|
|
|
dd89bb |
*ch = (char)(0x80 | wx);
|
|
|
dd89bb |
} else if ((*wch < 0xD800) || (*wch >= 0xE000)) {
|
|
|
dd89bb |
/* from: zzzzyyyy yyxxxxxx (little endian) */
|
|
|
dd89bb |
/* to: 1110zzzz 10yyyyyy 10xxxxxx (utf-8) */
|
|
|
dd89bb |
wz = *wch;
|
|
|
dd89bb |
wz >>= 12;
|
|
|
dd89bb |
|
|
|
dd89bb |
wy = *wch;
|
|
|
dd89bb |
wy <<= 4;
|
|
|
dd89bb |
wy >>= 10;
|
|
|
dd89bb |
|
|
|
dd89bb |
wx = *wch;
|
|
|
dd89bb |
wx <<= 10;
|
|
|
dd89bb |
wx >>= 10;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* write the z part */
|
|
|
dd89bb |
*ch = (char)(0xE0 | wz);
|
|
|
dd89bb |
ch++;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* write the y part */
|
|
|
dd89bb |
*ch = (char)(0x80 | wy);
|
|
|
dd89bb |
ch++;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* write the x part */
|
|
|
dd89bb |
*ch = (char)(0x80 | wx);
|
|
|
dd89bb |
} else {
|
|
|
dd89bb |
/* from: 110110ww wwzzzzyy 110111yy yyxxxxxx (little endian) */
|
|
|
dd89bb |
/* to: 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx (utf-8) */
|
|
|
dd89bb |
|
|
|
dd89bb |
/* low two bytes */
|
|
|
dd89bb |
wx = *wch;
|
|
|
dd89bb |
wx <<= 10;
|
|
|
dd89bb |
wx >>= 10;
|
|
|
dd89bb |
|
|
|
dd89bb |
wy_low = *wch;
|
|
|
dd89bb |
wy_low <<= 6;
|
|
|
dd89bb |
wy_low >>= 12;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* (surrogate pair) */
|
|
|
dd89bb |
wch++;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* high two bytes */
|
|
|
dd89bb |
wy_high = *wch;
|
|
|
dd89bb |
wy_high <<= 14;
|
|
|
dd89bb |
wy_high >>= 10;
|
|
|
dd89bb |
|
|
|
dd89bb |
wz = *wch;
|
|
|
dd89bb |
wz <<= 10;
|
|
|
dd89bb |
wz >>= 12;
|
|
|
dd89bb |
wz <<= 2;
|
|
|
dd89bb |
|
|
|
dd89bb |
ww = *wch;
|
|
|
dd89bb |
ww <<= 6;
|
|
|
dd89bb |
ww >>= 12;
|
|
|
dd89bb |
|
|
|
dd89bb |
uuuuu = ww + 1;
|
|
|
dd89bb |
u_high = uuuuu >> 2;
|
|
|
dd89bb |
u_low = ((uuuuu << 14) >> 10);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* 1st byte: 11110uuu */
|
|
|
dd89bb |
*ch = (char)(0xF0 | u_high);
|
|
|
dd89bb |
ch++;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* 2nd byte: 10uuzzzz */
|
|
|
dd89bb |
*ch = (char)(0x80 | u_low | wz);
|
|
|
dd89bb |
ch++;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* 3rd byte: 10yyyyyy */
|
|
|
dd89bb |
*ch = (char)(0x80 | wy_low | wy_high);
|
|
|
dd89bb |
ch++;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* 4th byte: 10xxxxxx */
|
|
|
dd89bb |
*ch = (char)(0x80 | wx);
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
ch++;
|
|
|
dd89bb |
wch++;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
if (*wch)
|
|
|
dd89bb |
return NT_STATUS_BUFFER_TOO_SMALL;
|
|
|
dd89bb |
|
|
|
dd89bb |
ch++;
|
|
|
dd89bb |
arrv++;
|
|
|
dd89bb |
warrv++;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
*bytes_written = (size_t)(ch - (uint8_t *)buffer);
|
|
|
dd89bb |
|
|
|
dd89bb |
return NT_STATUS_SUCCESS;
|
|
|
dd89bb |
}
|