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