1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 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 
odr_nullval(void)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 
odr_errmsg(int n)52 char *odr_errmsg(int n)
53 {
54     return odr_errlist[n];
55 }
56 
odr_perror(ODR o,const char * message)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 
odr_geterror(ODR o)78 int odr_geterror(ODR o)
79 {
80     return o->error;
81 }
82 
odr_geterrorx(ODR o,int * x)83 int odr_geterrorx(ODR o, int *x)
84 {
85     if (x)
86         *x = o->op->error_id;
87     return o->error;
88 }
89 
odr_getelement(ODR o)90 const char *odr_getelement(ODR o)
91 {
92     return o->op->element;
93 }
94 
odr_get_element_path(ODR o)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 
odr_seterror(ODR o,int error,int id)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 
odr_setelement(ODR o,const char * element)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 
odr_FILE_write(ODR o,void * handle,int type,const char * buf,int len)134 void odr_FILE_write(ODR o, void *handle, int type,
135                     const char *buf, int len)
136 {
137     int i;
138     for (i = 0; i < len; i++)
139     {
140         unsigned c = ((const unsigned char *) buf)[i];
141         if (i == 20000 && len > 31000)
142         {
143             fputs(" ..... ", (FILE*) handle);
144                 i = len - 1000;
145         }
146         if (strchr("\r\n\f\t", c) || (c >= ' ' && c <= 126))
147             putc(c, (FILE*) handle);
148         else
149         {
150             char x[5];
151             sprintf(x, "\\X%02X", c);
152             fputs(x, (FILE*) handle);
153         }
154     }
155 }
156 
odr_FILE_close(void * handle)157 void odr_FILE_close(void *handle)
158 {
159     FILE *f = (FILE *) handle;
160     if (f && f != stderr && f != stdout)
161         fclose(f);
162 }
163 
odr_setprint(ODR o,FILE * file)164 void odr_setprint(ODR o, FILE *file)
165 {
166     odr_set_stream(o, file, odr_FILE_write, odr_FILE_close);
167 }
168 
odr_setprint_noclose(ODR o,FILE * file)169 void odr_setprint_noclose(ODR o, FILE *file)
170 {
171     odr_set_stream(o, file, odr_FILE_write, 0);
172 }
173 
odr_set_stream(ODR o,void * handle,void (* stream_write)(ODR o,void * handle,int type,const char * buf,int len),void (* stream_close)(void * handle))174 void odr_set_stream(ODR o, void *handle,
175                     void (*stream_write)(ODR o,
176                                          void *handle, int type,
177                                          const char *buf, int len),
178                     void (*stream_close)(void *handle))
179 {
180     o->op->print = (FILE*) handle;
181     o->op->stream_write = stream_write;
182     o->op->stream_close = stream_close;
183 }
184 
odr_set_charset(ODR o,const char * to,const char * from)185 int odr_set_charset(ODR o, const char *to, const char *from)
186 {
187     if (o->op->iconv_handle)
188         yaz_iconv_close (o->op->iconv_handle);
189     o->op->iconv_handle = 0;
190     if (to && from)
191     {
192         o->op->iconv_handle = yaz_iconv_open(to, from);
193         if (o->op->iconv_handle == 0)
194             return -1;
195     }
196     return 0;
197 }
198 
199 
odr_createmem(int direction)200 ODR odr_createmem(int direction)
201 {
202     ODR o;
203     if (!log_level_initialized)
204     {
205         log_level = yaz_log_module_level("odr");
206         log_level_initialized = 1;
207     }
208 
209     if (!(o = (ODR) xmalloc(sizeof(*o))))
210         return 0;
211     o->op = (struct Odr_private *) xmalloc(sizeof(*o->op));
212     o->direction = direction;
213     o->op->buf = 0;
214     o->op->size = o->op->pos = o->op->top = 0;
215     o->op->can_grow = 1;
216     o->mem = nmem_create();
217     o->op->enable_bias = 1;
218     o->op->odr_ber_tag.lclass = -1;
219     o->op->iconv_handle = 0;
220     odr_setprint_noclose(o, stderr);
221     odr_reset(o);
222     yaz_log(log_level, "odr_createmem dir=%d o=%p", direction, o);
223     return o;
224 }
225 
odr_reset(ODR o)226 void odr_reset(ODR o)
227 {
228     if (!log_level_initialized)
229     {
230         log_level = yaz_log_module_level("odr");
231         log_level_initialized = 1;
232     }
233 
234     odr_seterror(o, ONONE, 0);
235     o->op->bp = o->op->buf;
236     odr_seek(o, ODR_S_SET, 0);
237     o->op->top = 0;
238     o->op->t_class = -1;
239     o->op->t_tag = -1;
240     o->op->indent = 0;
241     o->op->stack_first = 0;
242     o->op->stack_top = 0;
243     o->op->tmp_names_sz = 0;
244     o->op->tmp_names_buf = 0;
245     nmem_reset(o->mem);
246     o->op->choice_bias = -1;
247     o->op->lenlen = 1;
248     if (o->op->iconv_handle != 0)
249         yaz_iconv(o->op->iconv_handle, 0, 0, 0, 0);
250     yaz_log(log_level, "odr_reset o=%p", o);
251 }
252 
odr_destroy(ODR o)253 void odr_destroy(ODR o)
254 {
255     nmem_destroy(o->mem);
256     if (o->op->buf && o->op->can_grow)
257        xfree(o->op->buf);
258     if (o->op->stream_close)
259         o->op->stream_close(o->op->print);
260     if (o->op->iconv_handle != 0)
261         yaz_iconv_close(o->op->iconv_handle);
262     xfree(o->op);
263     xfree(o);
264     yaz_log(log_level, "odr_destroy o=%p", o);
265 }
266 
odr_setbuf(ODR o,char * buf,int len,int can_grow)267 void odr_setbuf(ODR o, char *buf, int len, int can_grow)
268 {
269     odr_seterror(o, ONONE, 0);
270     o->op->bp = buf;
271     o->op->buf = buf;
272     o->op->can_grow = can_grow;
273     o->op->top = o->op->pos = 0;
274     o->op->size = len;
275 }
276 
odr_getbuf(ODR o,int * len,int * size)277 char *odr_getbuf(ODR o, int *len, int *size)
278 {
279     *len = o->op->top;
280     if (size)
281         *size = o->op->size;
282     return o->op->buf;
283 }
284 
odr_offset(ODR o)285 int odr_offset(ODR o)
286 {
287     return o->op->bp - o->op->buf;
288 }
289 
odr_printf(ODR o,const char * fmt,...)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 
309