a64648a606ab2ca6f5cf3d33a8228f05ef67221e
[yaz-moved-to-github.git] / src / odr_oct.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file odr_oct.c
7  * \brief Implements ODR OCTET codec
8  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include "odr-priv.h"
14
15 /*
16  * Top level octet string en/decoder.
17  * Returns 1 on success, 0 on error.
18  */
19 int odr_octetstring(ODR o, Odr_oct **p, int opt, const char *name)
20 {
21     int res, cons = 0;
22
23     if (o->error)
24         return 0;
25     if (o->op->t_class < 0)
26     {
27         o->op->t_class = ODR_UNIVERSAL;
28         o->op->t_tag = ODR_OCTETSTRING;
29     }
30     res = ber_tag(o, p, o->op->t_class, o->op->t_tag, &cons, opt, name);
31     if (res < 0)
32         return 0;
33     if (!res)
34         return odr_missing(o, opt, name);
35     if (o->direction == ODR_PRINT)
36     {
37         odr_prname(o, name);
38         odr_printf(o, "OCTETSTRING(len=%d) ", (*p)->len);
39
40         o->op->stream_write(o, o->op->print, ODR_OCTETSTRING,
41                             (char*) (*p)->buf, (*p)->len);
42         odr_printf(o, "\n");
43         return 1;
44     }
45     if (o->direction == ODR_DECODE)
46     {
47         *p = (Odr_oct *)odr_malloc(o, sizeof(Odr_oct));
48 #if OCT_SIZE
49         (*p)->size= 0;
50 #endif
51         (*p)->len = 0;
52         (*p)->buf = 0;
53     }
54     if (ber_octetstring(o, *p, cons))
55         return 1;
56     odr_seterror(o, OOTHER, 43);
57     return 0;
58 }
59
60 /*
61  * Friendlier interface to octetstring.
62  */
63 int odr_cstring(ODR o, char **p, int opt, const char *name)
64 {
65     int cons = 0, res;
66     Odr_oct *t;
67
68     if (o->error)
69         return 0;
70     if (o->op->t_class < 0)
71     {
72         o->op->t_class = ODR_UNIVERSAL;
73         o->op->t_tag = ODR_OCTETSTRING;
74     }
75     res = ber_tag(o, p, o->op->t_class, o->op->t_tag, &cons, opt, name);
76     if (res < 0)
77         return 0;
78     if (!res)
79         return odr_missing(o, opt, name);
80     if (o->direction == ODR_PRINT)
81     {
82         odr_prname(o, name);
83         odr_printf(o, "'%s'\n", *p);
84         return 1;
85     }
86     t = (Odr_oct *)odr_malloc(o, sizeof(Odr_oct)); /* wrapper for octstring */
87     if (o->direction == ODR_ENCODE)
88     {
89         t->buf = *p;
90         t->len = strlen(*p);
91 #if OCT_SIZE
92         t->size = t->len;
93 #endif
94     }
95     else
96     {
97 #if OCT_SIZE
98         t->size= 0;
99 #endif
100         t->len = 0;
101         t->buf = 0;
102     }
103     if (!ber_octetstring(o, t, cons))
104         return 0;
105     if (o->direction == ODR_DECODE)
106     {
107         *p = (char *) t->buf;
108         *(*p + t->len) = '\0';  /* ber_octs reserves space for this */
109     }
110     return 1;
111 }
112
113 /*
114  * iconv interface to octetstring.
115  */
116 int odr_iconv_string(ODR o, char **p, int opt, const char *name)
117 {
118     int cons = 0, res;
119     Odr_oct *t;
120
121     if (o->error)
122         return 0;
123     if (o->op->t_class < 0)
124     {
125         o->op->t_class = ODR_UNIVERSAL;
126         o->op->t_tag = ODR_OCTETSTRING;
127     }
128     res = ber_tag(o, p, o->op->t_class, o->op->t_tag, &cons, opt, name);
129     if (res < 0)
130         return 0;
131     if (!res)
132         return odr_missing(o, opt, name);
133     if (o->direction == ODR_PRINT)
134     {
135         odr_prname(o, name);
136         odr_printf(o, "'%s'\n", *p);
137         return 1;
138     }
139     t = (Odr_oct *)odr_malloc(o, sizeof(Odr_oct)); /* wrapper for octstring */
140     if (o->direction == ODR_ENCODE)
141     {
142         t->buf = 0;
143
144         if (o->op->iconv_handle != 0)
145         {
146             size_t inleft = strlen(*p);
147             char *inbuf = *p;
148             size_t outleft = 4 * inleft + 2;
149             char *outbuf = (char *) odr_malloc (o, outleft);
150             size_t ret;
151
152             t->buf = outbuf;
153
154             ret = yaz_iconv(o->op->iconv_handle, &inbuf, &inleft,
155                             &outbuf, &outleft);
156             if (ret == (size_t)(-1))
157             {
158                 odr_seterror(o, ODATA, 44);
159                 return 0;
160             }
161             ret = yaz_iconv(o->op->iconv_handle, 0, 0,
162                             &outbuf, &outleft);
163
164             if (ret == (size_t)(-1))
165             {
166                 odr_seterror(o, ODATA, 44);
167                 return 0;
168             }
169             t->len = outbuf - (char*) t->buf;
170 #if OCT_SIZE
171             t->size = t->len;
172 #endif
173         }
174         if (!t->buf)
175         {
176             t->buf = *p;
177             t->len = strlen(*p);
178 #if OCT_SIZE
179             t->size = t->len;
180 #endif
181         }
182     }
183     else
184     {
185 #if OCT_SIZE
186         t->size= 0;
187 #endif
188         t->len = 0;
189         t->buf = 0;
190     }
191     if (!ber_octetstring(o, t, cons))
192         return 0;
193     if (o->direction == ODR_DECODE)
194     {
195         *p = 0;
196
197         if (o->op->iconv_handle != 0)
198         {
199             size_t inleft = t->len;
200             char *inbuf = (char *) t->buf;
201             size_t outleft = 4 * inleft + 2;
202             char *outbuf = (char *) odr_malloc (o, outleft);
203             size_t ret;
204
205             *p = outbuf;
206
207             ret = yaz_iconv (o->op->iconv_handle, &inbuf, &inleft,
208                              &outbuf, &outleft);
209             if (ret == (size_t)(-1))
210             {
211                 odr_seterror(o, ODATA, 45);
212                 return 0;
213             }
214             ret = yaz_iconv(o->op->iconv_handle, 0, 0,
215                             &outbuf, &outleft);
216             if (ret == (size_t)(-1))
217             {
218                 odr_seterror(o, ODATA, 45);
219                 return 0;
220             }
221             inleft = outbuf - (char*) *p;
222
223             (*p)[inleft] = '\0';    /* null terminate it */
224         }
225         if (!*p)
226         {
227             *p = (char *) t->buf;
228             *(*p + t->len) = '\0';  /* ber_octs reserves space for this */
229         }
230     }
231     return 1;
232 }
233 /*
234  * Local variables:
235  * c-basic-offset: 4
236  * c-file-style: "Stroustrup"
237  * indent-tabs-mode: nil
238  * End:
239  * vim: shiftwidth=4 tabstop=8 expandtab
240  */
241