/* -*- c-basic-offset: 8 -*-
   rdesktop: A Remote Desktop Protocol client.
   Generic utility functions
   Copyright 2013 Henrik Andersson <hean01@cendio.se> for Cendio AB

   This program 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 3 of the License, or
   (at your option) any later version.

   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
 * Oracle GPL Disclaimer: For the avoidance of doubt, except that if any license choice
 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
 * the General Public License version 2 (GPLv2) at this time for any software where
 * a choice of GPL license versions is made available with the language indicating
 * that GPLv2 or any later version may be used, or where a choice of which version
 * of the GPL is applied is otherwise unspecified.
 */

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
#ifdef HAVE_ICONV_H
#include <iconv.h>
#endif
#include "rdesktop.h"


#ifdef HAVE_ICONV
extern char g_codepage[16];
static RD_BOOL g_iconv_works = True;
#endif



char *
utils_string_escape(const char *str)
{
	const char *p;
	char *pe, *e, esc[4];
	size_t es;
	int cnt;

	/* count indices */
	cnt = 0;
	p = str;
	while (*(p++) != '\0')
		if ((unsigned char) *p < 32 || *p == '%')
			cnt++;

	/* if no characters needs escaping return copy of str */
	if (cnt == 0)
		return strdup(str);

	/* allocate new mem for result */
	es = strlen(str) + (cnt * 3) + 1;
	pe = e = xmalloc(es);
	memset(e, 0, es);
	p = str;
	while (*p != '\0')
	{
		if ((unsigned char) *p < 32 || *p == '%')
		{
			snprintf(esc, 4, "%%%02X", *p);
			memcpy(pe, esc, 3);
			pe += 3;
		}
		else
		{
			*pe = *p;
			pe++;
		}

		p++;
	}

	return e;
}

char *
utils_string_unescape(const char *str)
{
	char *ns, *ps, *pd, c;

	ns = xmalloc(strlen(str) + 1);
	memcpy(ns, str, strlen(str) + 1);
	ps = pd = ns;

	while (*ps != '\0')
	{
		/* check if found escaped character */
		if (ps[0] == '%')
		{
			if (sscanf(ps, "%%%2hhX", &c) == 1)
			{
				pd[0] = c;
				ps += 3;
				pd++;
				continue;
			}
		}

		/* just copy over the char */
		*pd = *ps;
		ps++;
		pd++;
	}
	pd[0] = '\0';

	return ns;
}

int
utils_mkdir_safe(const char *path, int mask)
{
	int res = 0;
	struct stat st;

	res = stat(path, &st);
	if (res == -1)
		return mkdir(path, mask);

	if (!S_ISDIR(st.st_mode))
	{
		errno = EEXIST;
		return -1;
	}

	return 0;
}

int
utils_mkdir_p(const char *path, int mask)
{
	int res;
	char *ptok;
	char pt[PATH_MAX];
	char bp[PATH_MAX];

	if (!path || strlen(path) == 0)
	{
		errno = EINVAL;
		return -1;
	}
	if (strlen(path) > PATH_MAX)
	{
		errno = E2BIG;
		return -1;
	}

	res = 0;
	pt[0] = bp[0] = '\0';
	strcpy(bp, path);

	ptok = strtok(bp, "/");
	if (ptok == NULL)
		return utils_mkdir_safe(path, mask);

	do
	{
		if (ptok != bp)
			strcat(pt, "/");

		strcat(pt, ptok);
		res = utils_mkdir_safe(pt, mask);
		if (res != 0)
			return res;

	}
	while ((ptok = strtok(NULL, "/")) != NULL);

	return 0;
}

/* Convert from system locale string to utf-8 */
int
utils_locale_to_utf8(const char *src, size_t is, char *dest, size_t os)
{
#ifdef HAVE_ICONV
	static iconv_t *iconv_h = (iconv_t) - 1;
	if (strncmp(g_codepage, "UTF-8", strlen("UTF-8")) == 0)
		goto pass_trough_as_is;

	if (g_iconv_works == False)
		goto pass_trough_as_is;

	/* if not already initialize */
	if (iconv_h == (iconv_t) - 1)
	{
		if ((iconv_h = iconv_open("UTF-8", g_codepage)) == (iconv_t) - 1)
		{
			warning("utils_string_to_utf8: iconv_open[%s -> %s] fail %p\n",
				g_codepage, "UTF-8", iconv_h);

			g_iconv_works = False;
			goto pass_trough_as_is;
		}
	}

	/* convert string */
	if (iconv(iconv_h, (ICONV_CONST char **) &src, &is, &dest, &os) == (size_t) - 1)
	{
		iconv_close(iconv_h);
		iconv_h = (iconv_t) - 1;
		warning("utils_string_to_utf8: iconv(1) fail, errno %d\n", errno);

		g_iconv_works = False;
		goto pass_trough_as_is;
	}

	/* Out couldn't hold the entire convertion */
	if (is != 0)
		return -1;

#endif
      pass_trough_as_is:
	/* can dest hold strcpy of src */
	if (os < (strlen(src) + 1))
		return -1;

	memcpy(dest, src, strlen(src) + 1);
	return 0;
}
