gitg-convert.vala 2.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
/*
 * This file is part of gitg
 *
 * Copyright (C) 2015 - Jesse van den Kieboom
 *
 * gitg is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * gitg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with gitg. If not, see <http://www.gnu.org/licenses/>.
 */

namespace Gitg.Convert
{
	private void utf8_validate_fallback(ref string text, ssize_t size)
	{
		char *end;

		while (!text.validate(size, out end))
		{
			*end = '?';
		}
	}

	private string convert_fallback(string text, ssize_t size, string fallback)
	{
		string res = "";
		size_t read;

		var str = new StringBuilder();

		while (true)
		{
			try
			{
				res = GLib.convert(text, size, "UTF-8", "ASCII", out read);
				break;
			}
			catch
			{
				try
				{
					str.append(GLib.convert(text, (ssize_t)read, "UTF-8", "ASCII"));
				} catch {}

				str.append(fallback);

				text = (string)((uint8[])text)[(read + 1):size];
				size -= (ssize_t)read;
			}
		}

		str.append(res);

		var retval = str.str;
		Convert.utf8_validate_fallback(ref retval, str.len);

		return retval;
	}

	private bool convert_and_check(string text, ssize_t size, string from_charset, out string? ret)
	{
		size_t read, written;

		ret = null;

		try
		{
			ret = GLib.convert(text, size, "UTF-8", from_charset, out read, out written);

			if (read == size)
			{
				Convert.utf8_validate_fallback(ref ret, (ssize_t)written);
				return true;
			}
		}
		catch {}

		return false;
	}


	public string utf8(string str, ssize_t size = -1, string? from_charset = null)
	{
		if (size == -1)
		{
			size = str.length;
		}

		if (from_charset == null)
		{
			if (str.validate(size))
			{
				return str[0:size];
			}
		}
		else
		{
			string ret;

			if (from_charset.ascii_casecmp("UTF-8") == 0)
			{
				ret = str[0:size];
				Convert.utf8_validate_fallback(ref ret, size);

				return ret;
			}

			if (Convert.convert_and_check(str, size, from_charset, out ret))
			{
				return ret;
			}
		}

		string locale_charset;

		if (!GLib.get_charset(out locale_charset))
		{
			string ret;

			if (Convert.convert_and_check(str, size, locale_charset, out ret))
			{
				return ret;
			}
		}

		return Convert.convert_fallback(str, size, "?");
	}
}

/* ex:set ts=4 noet: */