utf-conv.c 3.24 KB
Newer Older
1
/*
Edward Thomson committed
2
 * Copyright (C) the libgit2 contributors. All rights reserved.
3 4 5 6 7
 *
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
 */

8 9
#include "utf-conv.h"

10 11 12 13 14 15 16 17
GIT_INLINE(void) git__set_errno(void)
{
	if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
		errno = ENAMETOOLONG;
	else
		errno = EINVAL;
}

18 19 20 21 22 23 24 25 26 27 28
int git_utf8_to_16(wchar_t *dest, size_t dest_size, const char *src)
{
	/* Length of -1 indicates NULL termination of the input string. */
	return git_utf8_to_16_with_len(dest, dest_size, src, -1);
}

int git_utf8_to_16_with_len(
	wchar_t *dest,
	size_t _dest_size,
	const char *src,
	int src_len)
29
{
30
	int dest_size = (int)min(_dest_size, INT_MAX);
31 32
	int len;

33 34 35 36 37 38 39 40 41 42
	/*
	 * Subtract 1 from the result to turn 0 into -1 (an error code) and
	 * to not count the NULL terminator as part of the string's length.
	 * MultiByteToWideChar never returns int's minvalue, so underflow
	 * is not possible.
	 */
	len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
		src, src_len, dest, dest_size) - 1;

	if (len < 0)
43 44 45
		git__set_errno();

	return len;
46 47
}

48
int git_utf8_from_16(char *dest, size_t dest_size, const wchar_t *src)
49
{
50 51 52 53 54 55 56 57 58 59 60
	/* Length of -1 indicates NULL termination of the input string. */
	return git_utf8_from_16_with_len(dest, dest_size, src, -1);
}

int git_utf8_from_16_with_len(
	char *dest,
	size_t _dest_size,
	const wchar_t *src,
	int src_len)
{
	int dest_size = (int)min(_dest_size, INT_MAX);
61 62
	int len;

63 64 65 66 67 68 69 70 71 72
	/*
	 * Subtract 1 from the result to turn 0 into -1 (an error code) and
	 * to not count the NULL terminator as part of the string's length.
	 * WideCharToMultiByte never returns int's minvalue, so underflow
	 * is not possible.
	 */
	len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
		src, src_len, dest, dest_size, NULL, NULL) - 1;

	if (len < 0)
73 74 75
		git__set_errno();

	return len;
76 77
}

78 79 80 81 82 83 84
int git_utf8_to_16_alloc(wchar_t **dest, const char *src)
{
	/* Length of -1 indicates NULL termination of the input string. */
	return git_utf8_to_16_alloc_with_len(dest, src, -1);
}

int git_utf8_to_16_alloc_with_len(wchar_t **dest, const char *src, int src_len)
85 86 87 88 89
{
	int utf16_size;

	*dest = NULL;

90 91
	utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
		src, src_len, NULL, 0);
92

93 94
	if (!utf16_size) {
		git__set_errno();
95
		return -1;
96
	}
97

98 99
	*dest = git__mallocarray(utf16_size, sizeof(wchar_t));
	GIT_ERROR_CHECK_ALLOC(*dest);
100

101 102
	utf16_size = git_utf8_to_16_with_len(*dest, (size_t)utf16_size,
		src, src_len);
103

104
	if (utf16_size < 0) {
105 106 107 108
		git__free(*dest);
		*dest = NULL;
	}

109
	return utf16_size;
110 111
}

112 113 114 115 116 117 118
int git_utf8_from_16_alloc(char **dest, const wchar_t *src)
{
	/* Length of -1 indicates NULL termination of the input string. */
	return git_utf8_from_16_alloc_with_len(dest, src, -1);
}

int git_utf8_from_16_alloc_with_len(char **dest, const wchar_t *src, int src_len)
119 120 121 122 123
{
	int utf8_size;

	*dest = NULL;

124 125
	utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
		src, src_len, NULL, 0, NULL, NULL);
126

127 128
	if (!utf8_size) {
		git__set_errno();
129
		return -1;
130
	}
131 132

	*dest = git__malloc(utf8_size);
133
	GIT_ERROR_CHECK_ALLOC(*dest);
134

135 136
	utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
		src, src_len, *dest, utf8_size, NULL, NULL);
137

138
	if (utf8_size < 0) {
139 140 141 142
		git__free(*dest);
		*dest = NULL;
	}

143
	return utf8_size;
144
}