1 /* Conversion between encodings.
2 Copyright (C) 2001,2002 The Genes Development Team
3 This file is part of the Gedcom parser library.
4 Contributed by Peter Verthez <Peter.Verthez@advalvas.be>, 2001.
6 The Gedcom parser library is free software; you can redistribute it
7 and/or modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The Gedcom parser library is distributed in the hope that it will be
12 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the Gedcom parser library; if not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29 #include "gedcom_internal.h"
33 #define ENCODING_CONF_FILE "gedcom.enc"
34 #define GCONV_SEARCH_PATH "GCONV_PATH"
37 static iconv_t cd_to_internal = (iconv_t) -1;
38 static ENCODING the_enc = ONE_BYTE;
39 static hash_t *encodings = NULL;
41 char* charwidth_string[] = { "1", "2_HILO", "2_LOHI" };
43 hnode_t *node_alloc(void *c __attribute__((unused)))
45 return malloc(sizeof *node_alloc(NULL));
48 void node_free(hnode_t *n, void *c __attribute__((unused)))
50 free((void*)hnode_getkey(n));
55 void add_encoding(char *gedcom_n, char* charwidth, char *iconv_n)
59 key = (char *) malloc(strlen(gedcom_n) + strlen(charwidth) + 3);
60 val = (char *) malloc(strlen(iconv_n) + 1);
62 /* sprintf is safe here (malloc'ed before) */
63 sprintf(key, "%s(%s)", gedcom_n, charwidth);
66 if (hash_lookup(encodings, key)) {
67 gedcom_warning(_("Duplicate entry found for encoding '%s', ignoring"),
73 hash_alloc_insert(encodings, key, val);
77 char* get_encoding(char* gedcom_n, ENCODING enc)
82 key = (char*)malloc(strlen(gedcom_n) + strlen(charwidth_string[enc]) + 3);
83 /* sprintf is safe here (malloc'ed before) */
84 sprintf(key, "%s(%s)", gedcom_n, charwidth_string[enc]);
86 node = hash_lookup(encodings, key);
89 return hnode_get(node);
92 gedcom_error(_("No encoding defined for '%s'"), gedcom_n);
97 void cleanup_encodings()
102 /* Let function be called before main() */
103 void update_gconv_search_path() __attribute__ ((constructor));
105 void update_gconv_search_path()
108 /* Add gedcom data directory to gconv search path */
109 gconv_path = getenv(GCONV_SEARCH_PATH);
110 if (gconv_path == NULL || strstr(gconv_path, PKGDATADIR) == NULL) {
111 char *new_gconv_path;
112 if (gconv_path == NULL) {
113 new_gconv_path = (char *)malloc(strlen(GCONV_SEARCH_PATH)
116 sprintf(new_gconv_path, "%s=%s", GCONV_SEARCH_PATH, PKGDATADIR);
119 new_gconv_path = (char *)malloc(strlen(GCONV_SEARCH_PATH)
123 sprintf(new_gconv_path, "%s=%s:%s",
124 GCONV_SEARCH_PATH, gconv_path, PKGDATADIR);
126 /* Ignore failures of putenv (can't do anything about it anyway) */
127 putenv(new_gconv_path);
131 void init_encodings()
133 if (encodings == NULL) {
135 char buffer[MAXBUF + 1];
136 char gedcom_n[MAXBUF + 1];
137 char charwidth[MAXBUF + 1];
138 char iconv_n[MAXBUF + 1];
140 atexit(cleanup_encodings);
142 encodings = hash_create(HASHCOUNT_T_MAX, NULL, NULL);
143 hash_set_allocator(encodings, node_alloc, node_free, NULL);
145 /* Open gedcom configuration file and read */
146 in = fopen(ENCODING_CONF_FILE, "r");
149 sprintf(path, "%s/%s", PKGDATADIR, ENCODING_CONF_FILE);
150 in = fopen(path, "r");
153 gedcom_warning(_("Could not open encoding configuration file '%s'"),
158 while (fgets(buffer, sizeof(buffer), in) != NULL) {
159 if (buffer[strlen(buffer) - 1] != '\n') {
160 gedcom_error(_("Line too long in encoding configuration file '%s'"),
164 else if ((buffer[0] != '#') && (strcmp(buffer, "\n") != 0)) {
165 if (sscanf(buffer, "%s %s %s", gedcom_n, charwidth, iconv_n) == 3) {
166 add_encoding(gedcom_n, charwidth, iconv_n);
169 gedcom_error(_("Missing data in encoding configuration file '%s'"),
180 void set_encoding_width(ENCODING enc)
185 static char conv_buf[MAXGEDCLINELEN * 2];
186 static size_t conv_buf_size;
188 int open_conv_to_internal(char* fromcode)
190 char *encoding = get_encoding(fromcode, the_enc);
191 if (cd_to_internal != (iconv_t) -1)
192 iconv_close(cd_to_internal);
193 if (encoding == NULL) {
194 cd_to_internal = (iconv_t) -1;
197 memset(conv_buf, 0, sizeof(conv_buf));
199 cd_to_internal = iconv_open(INTERNAL_ENCODING, encoding);
200 if (cd_to_internal == (iconv_t) -1) {
201 gedcom_error(_("Error opening conversion context for encoding %s: %s"),
202 encoding, strerror(errno));
205 return (cd_to_internal != (iconv_t) -1);
208 void close_conv_to_internal()
210 iconv_close(cd_to_internal);
211 cd_to_internal = (iconv_t) -1;
214 char* to_internal(char* str, size_t len,
215 char* output_buffer, size_t out_len)
217 size_t outsize = out_len;
218 char *wrptr = output_buffer;
219 char *rdptr = conv_buf;
220 /* set up input buffer (concatenate to what was left previous time) */
221 /* can't use strcpy, because possible null bytes from unicode */
222 memcpy(conv_buf + conv_buf_size, str, len);
223 conv_buf_size += len;
224 /* set up output buffer (empty it) */
225 memset(output_buffer, 0, out_len);
226 /* do the conversion */
227 iconv(cd_to_internal, &rdptr, &conv_buf_size, &wrptr, &outsize);
228 /* then shift what is left over to the head of the input buffer */
229 memmove(conv_buf, rdptr, conv_buf_size);
230 memset(conv_buf + conv_buf_size, 0, sizeof(conv_buf) - conv_buf_size);
231 return output_buffer;