Added skeleton for query charset conversion. Bug #977.
[yaz-moved-to-github.git] / src / odr.c
1 /*
2  * Copyright (C) 1995-2007, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: odr.c,v 1.16 2007-03-19 21:08:13 adam Exp $
6  *
7  */
8
9 /**
10  * \file odr.c
11  * \brief Implements fundamental ODR functionality
12  */
13
14 #if HAVE_CONFIG_H
15 #include <config.h>
16 #endif
17
18 #include <assert.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdarg.h>
22
23 #include <yaz/xmalloc.h>
24 #include <yaz/log.h>
25 #include <yaz/snprintf.h>
26 #include "odr-priv.h"
27
28 static int log_level=0;
29 static int log_level_initialized=0;
30
31 Odr_null *ODR_NULLVAL = (Odr_null *) "NULL";  /* the presence of a null value */
32
33 Odr_null *odr_nullval (void)
34 {
35     return ODR_NULLVAL;
36 }
37
38 char *odr_errlist[] =
39 {
40     "No (unknown) error",
41     "Memory allocation failed",
42     "System error",
43     "No space in buffer",
44     "Required data element missing",
45     "Unexpected tag",
46     "Other error",
47     "Protocol error",
48     "Malformed data",
49     "Stack overflow",
50     "Length of constructed type different from sum of members",
51     "Overflow writing definite length of constructed type",
52     "Bad HTTP Request"
53 };
54
55 char *odr_errmsg(int n)
56 {
57     return odr_errlist[n];
58 }
59
60 void odr_perror(ODR o, const char *message)
61 {
62     const char *e = odr_getelement(o);
63     const char **element_path = odr_get_element_path(o);
64     int err, x;
65
66     err =  odr_geterrorx(o, &x);
67     fprintf(stderr, "%s: %s (code %d:%d)", message, odr_errlist[err], err, x);
68     if (e && *e)
69         fprintf(stderr, " element %s", e);
70     
71     fprintf(stderr, "\n");
72     if (element_path)
73     {
74         fprintf(stderr, "Element path:");
75         while (*element_path)
76             fprintf(stderr, " %s", *element_path++);
77         fprintf(stderr, "\n");
78     }
79 }
80
81 int odr_geterror(ODR o)
82 {
83     return o->error;
84 }
85
86 int odr_geterrorx(ODR o, int *x)
87 {
88     if (x)
89         *x = o->op->error_id;
90     return o->error;
91 }
92
93 const char *odr_getelement(ODR o)
94 {
95     return o->op->element;
96 }
97
98 const char **odr_get_element_path(ODR o)
99 {
100     int cur_sz = 0;
101     struct odr_constack *st;
102
103     for (st = o->op->stack_top; st; st = st->prev)
104         cur_sz++;
105     if (o->op->tmp_names_sz < cur_sz + 1)
106     {
107         o->op->tmp_names_sz = 2 * cur_sz + 5;
108         o->op->tmp_names_buf = (const char **)
109             odr_malloc(o, o->op->tmp_names_sz * sizeof(char*));
110     }
111     o->op->tmp_names_buf[cur_sz] = 0;
112     for (st = o->op->stack_top; st; st = st->prev)
113     {
114         cur_sz--;
115         o->op->tmp_names_buf[cur_sz] = st->name;
116     }
117     assert(cur_sz == 0);
118     return o->op->tmp_names_buf;
119 }
120
121 void odr_seterror(ODR o, int error, int id)
122 {
123     o->error = error;
124     o->op->error_id = id;
125     o->op->element[0] = '\0';
126 }
127
128 void odr_setelement(ODR o, const char *element)
129 {
130     if (element)
131     {
132         strncpy(o->op->element, element, sizeof(o->op->element)-1);
133         o->op->element[sizeof(o->op->element)-1] = '\0';
134     }
135 }
136
137 void odr_FILE_write(ODR o, void *handle, int type,
138                     const char *buf, int len)
139 {
140     int i;
141 #if 0
142     if (type  == ODR_OCTETSTRING)
143     {
144         const char **stack_names = odr_get_element_path(o);
145         for (i = 0; stack_names[i]; i++)
146             fprintf((FILE*) handle, "[%s]", stack_names[i]);
147         fputs("\n", (FILE*) handle);
148     }
149 #endif
150     for (i = 0; i<len; i++)
151     {
152         unsigned c = ((const unsigned char *) buf)[i];
153         if (i == 2000 && len > 3100)
154         {
155             fputs(" ..... ", (FILE*) handle);
156                 i = len - 1000;
157         }
158         if (strchr("\r\n\f\t", c) || (c >= ' ' && c <= 126))
159             putc(c, (FILE*) handle);
160         else
161         {
162             char x[5];
163             sprintf(x, "\\X%02X", c);
164             fputs(x, (FILE*) handle);
165         }
166     }
167 }
168
169 void odr_FILE_close(void *handle)
170 {
171     FILE *f = (FILE *) handle;
172     if (f && f != stderr && f != stdout)
173         fclose(f);
174 }
175
176 void odr_setprint(ODR o, FILE *file)
177 {
178     odr_set_stream(o, file, odr_FILE_write, odr_FILE_close);
179 }
180
181 void odr_set_stream(ODR o, void *handle,
182                     void (*stream_write)(ODR o, 
183                                          void *handle, int type,
184                                          const char *buf, int len),
185                     void (*stream_close)(void *handle))
186 {
187     o->op->print = (FILE*) handle;
188     o->op->stream_write = stream_write;
189     o->op->stream_close = stream_close;
190 }
191
192 int odr_set_charset(ODR o, const char *to, const char *from)
193 {
194     if (o->op->iconv_handle)
195         yaz_iconv_close (o->op->iconv_handle);
196     o->op->iconv_handle = 0;
197     if (to && from)
198     {
199         o->op->iconv_handle = yaz_iconv_open (to, from);
200         if (o->op->iconv_handle == 0)
201             return -1;
202     }
203     return 0;
204 }
205
206
207 ODR odr_createmem(int direction)
208 {
209     ODR o;
210     if (!log_level_initialized)
211     {
212         log_level=yaz_log_module_level("odr");
213         log_level_initialized=1;
214     }
215
216     if (!(o = (ODR)xmalloc(sizeof(*o))))
217         return 0;
218     o->op = (struct Odr_private *) xmalloc (sizeof(*o->op));
219     o->direction = direction;
220     o->buf = 0;
221     o->size = o->pos = o->top = 0;
222     o->op->can_grow = 1;
223     o->mem = nmem_create();
224     o->op->enable_bias = 1;
225     o->op->odr_ber_tag.lclass = -1;
226     o->op->iconv_handle = 0;
227     odr_setprint(o, stderr);
228     odr_reset(o);
229     yaz_log (log_level, "odr_createmem dir=%d o=%p", direction, o);
230     return o;
231 }
232
233 void odr_reset(ODR o)
234 {
235     if (!log_level_initialized)
236     {
237         log_level=yaz_log_module_level("odr");
238         log_level_initialized=1;
239     }
240
241     odr_seterror(o, ONONE, 0);
242     o->bp = o->buf;
243     odr_seek(o, ODR_S_SET, 0);
244     o->top = 0;
245     o->op->t_class = -1;
246     o->op->t_tag = -1;
247     o->op->indent = 0;
248     o->op->stack_first = 0;
249     o->op->stack_top = 0;
250     o->op->tmp_names_sz = 0;
251     o->op->tmp_names_buf = 0;
252     nmem_reset(o->mem);
253     o->op->choice_bias = -1;
254     o->op->lenlen = 1;
255     if (o->op->iconv_handle != 0)
256         yaz_iconv(o->op->iconv_handle, 0, 0, 0, 0);
257     yaz_log (log_level, "odr_reset o=%p", o);
258 }
259     
260 void odr_destroy(ODR o)
261 {
262     nmem_destroy(o->mem);
263     if (o->buf && o->op->can_grow)
264        xfree(o->buf);
265     if (o->op->stream_close)
266         o->op->stream_close(o->op->print);
267     if (o->op->iconv_handle != 0)
268         yaz_iconv_close (o->op->iconv_handle);
269     xfree(o->op);
270     xfree(o);
271     yaz_log (log_level, "odr_destroy o=%p", o);
272 }
273
274 void odr_setbuf(ODR o, char *buf, int len, int can_grow)
275 {
276     odr_seterror(o, ONONE, 0);
277     o->bp = (unsigned char *) buf;
278
279     o->buf = (unsigned char *) buf;
280     o->op->can_grow = can_grow;
281     o->top = o->pos = 0;
282     o->size = len;
283 }
284
285 char *odr_getbuf(ODR o, int *len, int *size)
286 {
287     *len = o->top;
288     if (size)
289         *size = o->size;
290     return (char*) o->buf;
291 }
292
293 void odr_printf(ODR o, const char *fmt, ...)
294 {
295     va_list ap;
296     char buf[4096];
297
298     va_start(ap, fmt);
299     yaz_vsnprintf(buf, sizeof(buf), fmt, ap);
300     o->op->stream_write(o, o->op->print, ODR_VISIBLESTRING, buf, strlen(buf));
301     va_end(ap);
302 }
303 /*
304  * Local variables:
305  * c-basic-offset: 4
306  * indent-tabs-mode: nil
307  * End:
308  * vim: shiftwidth=4 tabstop=8 expandtab
309  */
310