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