Package list unrtf / debian/latest src / my_iconv.c
debian/latest

Tree @debian/latest (Download .tar.gz)

my_iconv.c @debian/latestraw · history · blame

/*----------------------------------------------------------------------
 * Module name:  my_iconv
 * Author name:  Arkadiusz Firus
 * Create date:  07 Sep 08
 * Purpose:    iconv handles
 *----------------------------------------------------------------------
 Changes:
 * 04 Jan 10, daved@physiol.usyd.edu.au: use path specfied with -P to
 *	load charmap file(s)
 * 07 Oct 11, jf@dockes.org, major changes to unicode translations
 *--------------------------------------------------------------------*/

#include <stdio.h>
#include <string.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <stdlib.h>
#include <errno.h>

#include "malloc.h"
#include "my_iconv.h"
#include "util.h"
#include "unicode.h"
#include "path.h"

extern int verbose_mode;

/* Convert from charmap file entry to charmap table one.
   1st byte in table entry is code length
*/
static char *
get_code_str(FILE *f, iconv_t desc)
{
	char *icp, *ocp0, *ocp;
	size_t ibytes, obytes;
	char *obuf;

	char *utf8 = get_unicode_utf8(f);
	if (utf8 == NULL || *utf8 == 0)
	{
		/* fprintf(stderr, "get_code_str: NULL entry\n");*/
		my_free(utf8);
		return NULL;
	}
#if 0 /* debug */
	fprintf(stderr, "get_code_str: utf8: ");
	for (ocp = utf8; *ocp; ocp++)
	{
		fprintf(stderr, "%x", (unsigned)*ocp);
	}
	fprintf(stderr, "\n");
#endif

	obytes = 10;
	ibytes = strlen(utf8);
	obuf = malloc(obytes);
	if (obuf == NULL)
	{
		my_free(utf8);
		return NULL;
	}
	icp = utf8;
	ocp0 = ocp = obuf + 1;
	if (iconv(desc, &icp, &ibytes, &ocp, &obytes) == -1)
	{
		/*        fprintf(stderr, "unrtf: my_iconv: iconv error\n");*/
		my_free(utf8);
		return NULL;
	}

	// Set 1st byte to length
	obuf[0] = ocp - ocp0;
	my_free(utf8);
	return obuf;
}

my_iconv_t
my_iconv_open(const char *tocode, const char *fromcode)
{
	FILE *f;
	my_iconv_t cd = MY_ICONV_T_CLEAR;
	int c, i;
	/*      fprintf(stderr, "my_iconv_open: from %s to %s\n", fromcode, tocode);*/
	if ((cd.desc = iconv_open(tocode, fromcode)) == (iconv_t) - 1)
	{
		char *path = search_in_path(fromcode, "charmap");
		if (path == NULL)
		{
			return cd;
		}
		if ((f = fopen(path, "r")) == NULL && verbose_mode)
		{
			fprintf(stderr, "failed to open charmap file %s\n", path);
		}

		if (f != NULL)
		{
			/* Open iconv utf8->tocode conversion */
			iconv_t desc;
			if ((desc = iconv_open(tocode, "UTF-8")) == (iconv_t) - 1)
			{
				fclose(f);
				return cd;
			}
			cd.char_table = (char **)my_malloc(char_table_size *
			                                   sizeof(char *));
			c = fgetc(f);

			for (i = 0; i < char_table_size && c != EOF; i++)
			{
				if (c == '<')
				{
					cd.char_table[i] = get_code_str(f, desc);
				}
				leave_line(f);//read up to including \n or eof
				c = fgetc(f);
			}
			iconv_close(desc);
			fclose(f);
		}

		my_free(path);
	}

	return cd;
}

size_t
my_iconv(my_iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
{
	int c, i;
	size_t result = 0;
	**outbuf = 0;
	if (cd.desc == (iconv_t) - 1)
	{
		if (cd.char_table != NULL)
		{
			while (*inbytesleft > 0 && *outbytesleft > 0)
			{
				c = **(unsigned char **)inbuf;
				if (cd.char_table[c] != NULL)
				{
					for (i = 0; i < cd.char_table[c][0] && *outbytesleft > 0; i++)
					{
						**outbuf = cd.char_table[c][i + 1];
						(*outbytesleft)--;
						(*outbuf)++;
					}
				}
				else
				{
					/*                    fprintf(stderr, "my_iconv: no conversion for 0x%x\n",
						      (unsigned)c);*/
					errno = EILSEQ;
					return (size_t) - 1;
				}

				(*inbuf)++;
				(*inbytesleft)--;
				result++;
			}

			if (*outbytesleft == 0 && *inbytesleft > 0)
			{
				errno = E2BIG;
				result = (size_t) - 1;
			}
		}
	}
	else
	{
		result = iconv(cd.desc, inbuf, inbytesleft, outbuf, outbytesleft);
	}

	return result;
}

my_iconv_t
my_iconv_close(my_iconv_t cd)
{
	int i;

	if (cd.char_table != NULL)
	{
		for (i = 0; i < char_table_size; i++)
		{
			if (cd.char_table[i] != NULL)
			{
				my_free(cd.char_table[i]);
			}
		}

		my_free((void *)cd.char_table);
		cd.char_table = NULL;
	}

	if (cd.desc != (iconv_t) - 1)
	{
		iconv_close(cd.desc);
		cd.desc = (iconv_t) - 1;
	}

	return cd;
}

int
my_iconv_is_valid(my_iconv_t cd)
{
	if (cd.desc != (iconv_t) - 1 || cd.char_table != NULL)
	{
		return 1;
	}

	return 0;
}

void
my_iconv_t_make_invalid(my_iconv_t *cd)
{
	cd->desc = (iconv_t) - 1;
	cd->char_table = NULL;
}