char* utf8_name;
};
+static wchar_t const native_local_path_prefix[] = { '\\', '\\', '?', '\\' };
+static wchar_t const native_unc_path_prefix[] = { '\\', '\\', '?', '\\', 'U', 'N', 'C', '\\' };
+
static void set_system_error(tr_error** error, DWORD code)
{
char* message;
/* Extending maximum path length limit up to ~32K. See "Naming Files, Paths, and Namespaces"
(https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx) for more info */
- wchar_t const local_prefix[] = { '\\', '\\', '?', '\\' };
- wchar_t const unc_prefix[] = { '\\', '\\', '?', '\\', 'U', 'N', 'C', '\\' };
-
bool const is_relative = tr_sys_path_is_relative(path);
bool const is_unc = is_unc_path(path);
/* `-2` for UNC since we overwrite existing prefix slashes */
- int const extra_chars_before = is_relative ? 0 : (is_unc ? TR_N_ELEMENTS(unc_prefix) - 2 : TR_N_ELEMENTS(local_prefix));
+ int const extra_chars_before = is_relative ? 0 : (is_unc ? TR_N_ELEMENTS(native_unc_path_prefix) - 2 :
+ TR_N_ELEMENTS(native_local_path_prefix));
/* TODO (?): TR_ASSERT(!is_relative); */
if (is_unc)
{
/* UNC path: "\\server\share" -> "\\?\UNC\server\share" */
- memcpy(wide_path, unc_prefix, sizeof(unc_prefix));
+ memcpy(wide_path, native_unc_path_prefix, sizeof(native_unc_path_prefix));
}
else
{
/* Local path: "C:" -> "\\?\C:" */
- memcpy(wide_path, local_prefix, sizeof(local_prefix));
+ memcpy(wide_path, native_local_path_prefix, sizeof(native_local_path_prefix));
}
}
return path_to_native_path_ex(path, 0, NULL);
}
+static char* native_path_to_path(wchar_t const* wide_path)
+{
+ if (wide_path == NULL)
+ {
+ return NULL;
+ }
+
+ bool const is_unc = wcsncmp(wide_path, native_unc_path_prefix, TR_N_ELEMENTS(native_unc_path_prefix)) == 0;
+ bool const is_local = !is_unc && wcsncmp(wide_path, native_local_path_prefix, TR_N_ELEMENTS(native_local_path_prefix)) == 0;
+
+ size_t const skip_chars = is_unc ? TR_N_ELEMENTS(native_unc_path_prefix) :
+ (is_local ? TR_N_ELEMENTS(native_local_path_prefix) : 0);
+
+ char* const path = tr_win32_native_to_utf8_ex(wide_path + skip_chars, -1, is_unc ? 2 : 0, 0, NULL);
+
+ if (is_unc && path != NULL)
+ {
+ path[0] = '\\';
+ path[1] = '\\';
+ }
+
+ return path;
+}
+
static tr_sys_file_t open_file(char const* path, DWORD access, DWORD disposition, DWORD flags, tr_error** error)
{
TR_ASSERT(path != NULL);
goto fail;
}
- /* Resolved path always begins with "\\?\", so skip those first four chars. */
- ret = tr_win32_native_to_utf8(wide_ret + 4, -1);
+ TR_ASSERT(wcsncmp(wide_ret, L"\\\\?\\", 4) == 0);
+
+ ret = native_path_to_path(wide_ret);
if (ret != NULL)
{
#ifdef _WIN32
char* tr_win32_native_to_utf8(wchar_t const* text, int text_size)
+{
+ return tr_win32_native_to_utf8_ex(text, text_size, 0, 0, NULL);
+}
+
+char* tr_win32_native_to_utf8_ex(wchar_t const* text, int text_size, int extra_chars_before, int extra_chars_after,
+ int* real_result_size)
{
char* ret = NULL;
int size;
+ if (text_size == -1)
+ {
+ text_size = wcslen(text);
+ }
+
size = WideCharToMultiByte(CP_UTF8, 0, text, text_size, NULL, 0, NULL, NULL);
if (size == 0)
goto fail;
}
- ret = tr_new(char, size + 1);
- size = WideCharToMultiByte(CP_UTF8, 0, text, text_size, ret, size, NULL, NULL);
+ ret = tr_new(char, size + extra_chars_before + extra_chars_after + 1);
+ size = WideCharToMultiByte(CP_UTF8, 0, text, text_size, ret + extra_chars_before, size, NULL, NULL);
if (size == 0)
{
goto fail;
}
- ret[size] = '\0';
+ ret[size + extra_chars_before + extra_chars_after] = '\0';
+
+ if (real_result_size != NULL)
+ {
+ *real_result_size = size;
+ }
return ret;