Conversion from ANSEL to Unicode (iconv module).
[gedcom-parse.git] / encoding.c
1 #include <string.h>
2 #include <iconv.h>
3 #include <search.h>
4 #include <stdio.h>
5 #include "gedcom.h"
6 #include "encoding.h"
7
8 #define INTERNAL_ENCODING "UTF8"
9 #define ENCODING_CONF_FILE "gedcom.enc"
10 #define MAXBUF 255
11
12 static iconv_t cd_to_internal = (iconv_t) -1;
13 static char int_buf[MAXGEDCLINELEN*2];
14 static void *encoding_mapping = NULL;
15
16 struct node {
17   char *gedcom_name;
18   char *iconv_name;
19 };
20
21 int node_compare(const void *node1, const void *node2)
22 {
23   return strcmp(((const struct node *) node1)->gedcom_name,
24                 ((const struct node *) node2)->gedcom_name);
25 }
26
27 void add_encoding(char *gedcom_n, char *iconv_n)
28 {
29   void **datum;
30   struct node *nodeptr = (struct node *) malloc(sizeof *nodeptr);
31   nodeptr->gedcom_name = (char *) malloc(strlen(gedcom_n) + 1);
32   nodeptr->iconv_name  = (char *) malloc(strlen(iconv_n) + 1);
33   strcpy(nodeptr->gedcom_name, gedcom_n);
34   strcpy(nodeptr->iconv_name, iconv_n);
35   datum = tsearch(nodeptr, &encoding_mapping, node_compare);
36   if ((datum == NULL) || (*datum != nodeptr)) {
37     gedcom_warning("Duplicate entry found for encoding '%s', ignoring",
38                    gedcom_n);
39   }
40 }
41
42 char* get_encoding(char* gedcom_n)
43 {
44   void **datum;
45   struct node search_node;
46   search_node.gedcom_name = gedcom_n;
47   datum = tfind(&search_node, &encoding_mapping, node_compare);
48   if (datum == NULL) {
49     gedcom_error("No encoding found for '%s'", gedcom_n);
50     return NULL;
51   }
52   else {
53     return ((const struct node *) *datum)->iconv_name;
54   }
55 }
56
57 void init_encodings()
58 {
59   if (encoding_mapping == NULL) {
60     FILE *in;
61     char buffer[MAXBUF + 1];
62     char gedcom_n[MAXBUF + 1];
63     char iconv_n[MAXBUF + 1];
64     in = fopen(ENCODING_CONF_FILE, "r");
65     if (in != NULL) {
66       while (fgets(buffer, sizeof(buffer), in) != NULL) {
67         if (buffer[strlen(buffer) - 1] != '\n') {
68           gedcom_error("Line too long in encoding configuration file '%s'",
69                        ENCODING_CONF_FILE);
70           return;
71         }
72         else if (buffer[0] != '#') {
73           if (sscanf(buffer, "%s %s", gedcom_n, iconv_n) == 2) {
74             add_encoding(gedcom_n, iconv_n);
75           }
76         }
77       }
78       fclose(in);
79     }
80     else {
81       gedcom_warning("Could not open encoding configuration file '%s'",
82                      ENCODING_CONF_FILE);
83     }
84   }
85 }
86
87 int open_conv_to_internal(char* fromcode)
88 {
89   char *encoding = get_encoding(fromcode);
90   if (cd_to_internal != (iconv_t) -1)
91     iconv_close(cd_to_internal);
92   if (encoding == NULL) {
93     cd_to_internal = (iconv_t) -1;
94   }
95   else {
96     cd_to_internal = iconv_open(INTERNAL_ENCODING, encoding);
97   }
98   return (cd_to_internal != (iconv_t) -1);  
99 }
100
101 void close_conv_to_internal()
102 {
103   iconv_close(cd_to_internal);
104   cd_to_internal = (iconv_t) -1;
105 }
106
107 char* to_internal(char* str, size_t len)
108 {
109   size_t insize = len;
110   size_t outsize = MAXGEDCLINELEN * 2;
111   char *wrptr = int_buf;
112   char *rdptr = str;
113   memset(int_buf, 0, sizeof(int_buf));
114   iconv(cd_to_internal, &rdptr, &insize, &wrptr, &outsize);
115   return int_buf;
116 }
117