Reworked odr_set_stream a bit, so that write handler now takes a
[yaz-moved-to-github.git] / src / odr_oct.c
1 /*
2  * Copyright (c) 1995-2004, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Id: odr_oct.c,v 1.3 2004-08-13 07:30:06 adam Exp $
6  */
7 #if HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10
11 #include <yaz/log.h>
12 #include "odr-priv.h"
13
14 /*
15  * Top level octet string en/decoder.
16  * Returns 1 on success, 0 on error.
17  */
18 int odr_octetstring(ODR o, Odr_oct **p, int opt, const char *name)
19 {
20     int res, cons = 0;
21
22     if (o->error)
23         return 0;
24     if (o->t_class < 0)
25     {
26         o->t_class = ODR_UNIVERSAL;
27         o->t_tag = ODR_OCTETSTRING;
28     }
29     if ((res = ber_tag(o, p, o->t_class, o->t_tag, &cons, opt, name)) < 0)
30         return 0;
31     if (!res)
32         return odr_missing(o, opt, name);
33     if (o->direction == ODR_PRINT)
34     {
35         int i;
36         odr_prname(o, name);
37         odr_printf(o, "OCTETSTRING(len=%d) ", (*p)->len);
38
39         o->op->stream_write(o, o->print, ODR_OCTETSTRING,
40                             (*p)->buf, (*p)->len);
41         odr_printf(o, "\n");
42         return 1;
43     }
44     if (o->direction == ODR_DECODE)
45     {
46         *p = (Odr_oct *)odr_malloc(o, sizeof(Odr_oct));
47         (*p)->size= 0;
48         (*p)->len = 0;
49         (*p)->buf = 0;
50     }
51     if (ber_octetstring(o, *p, cons))
52         return 1;
53     odr_seterror(o, OOTHER, 43);
54     return 0;
55 }
56
57 /*
58  * Friendlier interface to octetstring.
59  */
60 int odr_cstring(ODR o, char **p, int opt, const char *name)
61 {
62     int cons = 0, res;
63     Odr_oct *t;
64
65     if (o->error)
66         return 0;
67     if (o->t_class < 0)
68     {
69         o->t_class = ODR_UNIVERSAL;
70         o->t_tag = ODR_OCTETSTRING;
71     }
72     if ((res = ber_tag(o, p, o->t_class, o->t_tag, &cons, opt, name)) < 0)
73         return 0;
74     if (!res)
75         return odr_missing(o, opt, name);
76     if (o->direction == ODR_PRINT)
77     {
78         odr_prname(o, name);
79         odr_printf(o, "'%s'\n", *p);
80         return 1;
81     }
82     t = (Odr_oct *)odr_malloc(o, sizeof(Odr_oct)); /* wrapper for octstring */
83     if (o->direction == ODR_ENCODE)
84     {
85         t->buf = (unsigned char *) *p;
86         t->size = t->len = strlen(*p);
87     }
88     else
89     {
90         t->size= 0;
91         t->len = 0;
92         t->buf = 0;
93     }
94     if (!ber_octetstring(o, t, cons))
95         return 0;
96     if (o->direction == ODR_DECODE)
97     {
98         *p = (char *) t->buf;
99         *(*p + t->len) = '\0';  /* ber_octs reserves space for this */
100     }
101     return 1;
102 }
103
104 /*
105  * iconv interface to octetstring.
106  */
107 int odr_iconv_string(ODR o, char **p, int opt, const char *name)
108 {
109     int cons = 0, res;
110     Odr_oct *t;
111
112     if (o->error)
113         return 0;
114     if (o->t_class < 0)
115     {
116         o->t_class = ODR_UNIVERSAL;
117         o->t_tag = ODR_OCTETSTRING;
118     }
119     if ((res = ber_tag(o, p, o->t_class, o->t_tag, &cons, opt, name)) < 0)
120         return 0;
121     if (!res)
122         return odr_missing(o, opt, name);
123     if (o->direction == ODR_PRINT)
124     {
125         odr_prname(o, name);
126         odr_printf(o, "'%s'\n", *p);
127         return 1;
128     }
129     t = (Odr_oct *)odr_malloc(o, sizeof(Odr_oct)); /* wrapper for octstring */
130     if (o->direction == ODR_ENCODE)
131     {
132         t->buf = 0;
133
134         if (o->op->iconv_handle != 0)
135         {
136             size_t inleft = strlen(*p);
137             char *inbuf = *p;
138             size_t outleft = 4 * inleft + 2;
139             char *outbuf = (char *) odr_malloc (o, outleft);
140             size_t ret;
141             
142             t->buf = (unsigned char *) outbuf;
143             
144             ret = yaz_iconv (o->op->iconv_handle, &inbuf, &inleft,
145                              &outbuf, &outleft);
146             if (ret == (size_t)(-1))
147             {
148                 odr_seterror(o, ODATA, 44);
149                 return 0;
150             }
151             t->size = t->len = outbuf - (char*) t->buf;
152         }
153         if (!t->buf)
154         {
155             t->buf = (unsigned char *) *p;
156             t->size = t->len = strlen(*p);
157         }
158     }
159     else
160     {
161         t->size= 0;
162         t->len = 0;
163         t->buf = 0;
164     }
165     if (!ber_octetstring(o, t, cons))
166         return 0;
167     if (o->direction == ODR_DECODE)
168     {
169         *p = 0;
170
171         if (o->op->iconv_handle != 0)
172         {
173             size_t inleft = t->len;
174             char *inbuf = (char *) t->buf;
175             size_t outleft = 4 * inleft + 2;
176             char *outbuf = (char *) odr_malloc (o, outleft);
177             size_t ret;
178
179             *p = outbuf;
180             
181             ret = yaz_iconv (o->op->iconv_handle, &inbuf, &inleft,
182                              &outbuf, &outleft);
183             if (ret == (size_t)(-1))
184             {
185                 odr_seterror(o, ODATA, 45);
186                 return 0;
187             }
188             inleft = outbuf - (char*) *p;
189             
190             (*p)[inleft] = '\0';    /* null terminate it */
191         }
192         if (!*p)
193         {
194             *p = (char *) t->buf;
195             *(*p + t->len) = '\0';  /* ber_octs reserves space for this */
196         }
197     }
198     return 1;
199 }