]> git.proxmox.com Git - libgit2.git/blobdiff - src/win32/utf-conv.c
New upstream version 1.4.3+dfsg.1
[libgit2.git] / src / win32 / utf-conv.c
index 3c8be81d1b9eb8dfc127d16fe1c2e8f798ad4341..4bde3023ab6b07905e2de6e82f15247f1c1b2a59 100644 (file)
 /*
- * Copyright (C) 2009-2012 the libgit2 contributors
+ * Copyright (C) the libgit2 contributors. All rights reserved.
  *
  * This file is part of libgit2, distributed under the GNU GPL v2 with
  * a Linking Exception. For full terms see the included COPYING file.
  */
 
-#include "common.h"
 #include "utf-conv.h"
 
-/*
- * Default codepage value
- */
-static int _active_codepage = CP_UTF8;
-
-void gitwin_set_codepage(unsigned int codepage)
+GIT_INLINE(void) git__set_errno(void)
 {
-       _active_codepage = codepage;
+       if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+               errno = ENAMETOOLONG;
+       else
+               errno = EINVAL;
 }
 
-unsigned int gitwin_get_codepage(void)
+/**
+ * Converts a UTF-8 string to wide characters.
+ *
+ * @param dest The buffer to receive the wide string.
+ * @param dest_size The size of the buffer, in characters.
+ * @param src The UTF-8 string to convert.
+ * @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure
+ */
+int git__utf8_to_16(wchar_t *dest, size_t dest_size, const char *src)
 {
-       return _active_codepage;
+       int len;
+
+       /* Length of -1 indicates NULL termination of the input string. 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 */
+       if ((len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, dest, (int)dest_size) - 1) < 0)
+               git__set_errno();
+
+       return len;
 }
 
-void gitwin_set_utf8(void)
+/**
+ * Converts a wide string to UTF-8.
+ *
+ * @param dest The buffer to receive the UTF-8 string.
+ * @param dest_size The size of the buffer, in bytes.
+ * @param src The wide string to convert.
+ * @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure
+ */
+int git__utf16_to_8(char *dest, size_t dest_size, const wchar_t *src)
 {
-       _active_codepage = CP_UTF8;
+       int len;
+
+       /* Length of -1 indicates NULL termination of the input string. 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 */
+       if ((len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, dest, (int)dest_size, NULL, NULL) - 1) < 0)
+               git__set_errno();
+
+       return len;
 }
 
-wchar_t* gitwin_to_utf16(const char* str)
+/**
+ * Converts a UTF-8 string to wide characters.
+ * Memory is allocated to hold the converted string.
+ * The caller is responsible for freeing the string with git__free.
+ *
+ * @param dest Receives a pointer to the wide string.
+ * @param src The UTF-8 string to convert.
+ * @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure
+ */
+int git__utf8_to_16_alloc(wchar_t **dest, const char *src)
 {
-       wchar_t* ret;
-       int cb;
+       int utf16_size;
+
+       *dest = NULL;
 
-       if (!str) {
-               return NULL;
+       /* Length of -1 indicates NULL termination of the input string */
+       utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, NULL, 0);
+
+       if (!utf16_size) {
+               git__set_errno();
+               return -1;
        }
 
-       cb = strlen(str) * sizeof(wchar_t);
-       if (cb == 0) {
-               ret = (wchar_t*)git__malloc(sizeof(wchar_t));
-               ret[0] = 0;
-               return ret;
+       if (!(*dest = git__mallocarray(utf16_size, sizeof(wchar_t)))) {
+               errno = ENOMEM;
+               return -1;
        }
 
-       /* Add space for null terminator */
-       cb += sizeof(wchar_t);
+       utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, *dest, utf16_size);
 
-       ret = (wchar_t*)git__malloc(cb);
+       if (!utf16_size) {
+               git__set_errno();
 
-       if (MultiByteToWideChar(_active_codepage, 0, str, -1, ret, cb) == 0) {
-               git__free(ret);
-               ret = NULL;
+               git__free(*dest);
+               *dest = NULL;
        }
 
-       return ret;
+       /* 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 */
+       return utf16_size - 1;
 }
 
-int gitwin_append_utf16(wchar_t *buffer, const char *str, size_t len)
+/**
+ * Converts a wide string to UTF-8.
+ * Memory is allocated to hold the converted string.
+ * The caller is responsible for freeing the string with git__free.
+ *
+ * @param dest Receives a pointer to the UTF-8 string.
+ * @param src The wide string to convert.
+ * @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure
+ */
+int git__utf16_to_8_alloc(char **dest, const wchar_t *src)
 {
-       return MultiByteToWideChar(_active_codepage, 0, str, -1, buffer, len);
-}
+       int utf8_size;
 
-char* gitwin_from_utf16(const wchar_t* str)
-{
-       char* ret;
-       int cb;
+       *dest = NULL;
+
+       /* Length of -1 indicates NULL termination of the input string */
+       utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, NULL, 0, NULL, NULL);
 
-       if (!str) {
-               return NULL;
+       if (!utf8_size) {
+               git__set_errno();
+               return -1;
        }
 
-       cb = wcslen(str) * sizeof(char);
-       if (cb == 0) {
-               ret = (char*)git__malloc(sizeof(char));
-               ret[0] = 0;
-               return ret;
+       *dest = git__malloc(utf8_size);
+
+       if (!*dest) {
+               errno = ENOMEM;
+               return -1;
        }
 
-       /* Add space for null terminator */
-       cb += sizeof(char);
+       utf8_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, *dest, utf8_size, NULL, NULL);
 
-       ret = (char*)git__malloc(cb);
+       if (!utf8_size) {
+               git__set_errno();
 
-       if (WideCharToMultiByte(_active_codepage, 0, str, -1, ret, cb, NULL, NULL) == 0) {
-               git__free(ret);
-               ret = NULL;
+               git__free(*dest);
+               *dest = NULL;
        }
 
-       return ret;
-
+       /* 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 */
+       return utf8_size - 1;
 }