Added skeleton for query charset conversion. Bug #977.
[yaz-moved-to-github.git] / src / odr_oct.c
1 /*
2  * Copyright (C) 1995-2007, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: odr_oct.c,v 1.11 2007-03-19 21:08:13 adam Exp $
6  */
7 /**
8  * \file odr_oct.c
9  * \brief Implements ODR OCTET codec
10  */
11 #if HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #include "odr-priv.h"
16
17 /*
18  * Top level octet string en/decoder.
19  * Returns 1 on success, 0 on error.
20  */
21 int odr_octetstring(ODR o, Odr_oct **p, int opt, const char *name)
22 {
23     int res, cons = 0;
24
25     if (o->error)
26         return 0;
27     if (o->op->t_class < 0)
28     {
29         o->op->t_class = ODR_UNIVERSAL;
30         o->op->t_tag = ODR_OCTETSTRING;
31     }
32     res = ber_tag(o, p, o->op->t_class, o->op->t_tag, &cons, opt, name);
33     if (res < 0)
34         return 0;
35     if (!res)
36         return odr_missing(o, opt, name);
37     if (o->direction == ODR_PRINT)
38     {
39         odr_prname(o, name);
40         odr_printf(o, "OCTETSTRING(len=%d) ", (*p)->len);
41
42         o->op->stream_write(o, o->op->print, ODR_OCTETSTRING,
43                             (char*) (*p)->buf, (*p)->len);
44         odr_printf(o, "\n");
45         return 1;
46     }
47     if (o->direction == ODR_DECODE)
48     {
49         *p = (Odr_oct *)odr_malloc(o, sizeof(Odr_oct));
50         (*p)->size= 0;
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 = (unsigned char *) *p;
90         t->size = t->len = strlen(*p);
91     }
92     else
93     {
94         t->size= 0;
95         t->len = 0;
96         t->buf = 0;
97     }
98     if (!ber_octetstring(o, t, cons))
99         return 0;
100     if (o->direction == ODR_DECODE)
101     {
102         *p = (char *) t->buf;
103         *(*p + t->len) = '\0';  /* ber_octs reserves space for this */
104     }
105     return 1;
106 }
107
108 /*
109  * iconv interface to octetstring.
110  */
111 int odr_iconv_string(ODR o, char **p, int opt, const char *name)
112 {
113     int cons = 0, res;
114     Odr_oct *t;
115
116     if (o->error)
117         return 0;
118     if (o->op->t_class < 0)
119     {
120         o->op->t_class = ODR_UNIVERSAL;
121         o->op->t_tag = ODR_OCTETSTRING;
122     }
123     res = ber_tag(o, p, o->op->t_class, o->op->t_tag, &cons, opt, name);
124     if (res < 0)
125         return 0;
126     if (!res)
127         return odr_missing(o, opt, name);
128     if (o->direction == ODR_PRINT)
129     {
130         odr_prname(o, name);
131         odr_printf(o, "'%s'\n", *p);
132         return 1;
133     }
134     t = (Odr_oct *)odr_malloc(o, sizeof(Odr_oct)); /* wrapper for octstring */
135     if (o->direction == ODR_ENCODE)
136     {
137         t->buf = 0;
138
139         if (o->op->iconv_handle != 0)
140         {
141             size_t inleft = strlen(*p);
142             char *inbuf = *p;
143             size_t outleft = 4 * inleft + 2;
144             char *outbuf = (char *) odr_malloc (o, outleft);
145             size_t ret;
146             
147             t->buf = (unsigned char *) outbuf;
148             
149             ret = yaz_iconv (o->op->iconv_handle, &inbuf, &inleft,
150                              &outbuf, &outleft);
151             if (ret == (size_t)(-1))
152             {
153                 odr_seterror(o, ODATA, 44);
154                 return 0;
155             }
156             t->size = t->len = outbuf - (char*) t->buf;
157         }
158         if (!t->buf)
159         {
160             t->buf = (unsigned char *) *p;
161             t->size = t->len = strlen(*p);
162         }
163     }
164     else
165     {
166         t->size= 0;
167         t->len = 0;
168         t->buf = 0;
169     }
170     if (!ber_octetstring(o, t, cons))
171         return 0;
172     if (o->direction == ODR_DECODE)
173     {
174         *p = 0;
175
176         if (o->op->iconv_handle != 0)
177         {
178             size_t inleft = t->len;
179             char *inbuf = (char *) t->buf;
180             size_t outleft = 4 * inleft + 2;
181             char *outbuf = (char *) odr_malloc (o, outleft);
182             size_t ret;
183
184             *p = outbuf;
185             
186             ret = yaz_iconv (o->op->iconv_handle, &inbuf, &inleft,
187                              &outbuf, &outleft);
188             if (ret == (size_t)(-1))
189             {
190                 odr_seterror(o, ODATA, 45);
191                 return 0;
192             }
193             inleft = outbuf - (char*) *p;
194             
195             (*p)[inleft] = '\0';    /* null terminate it */
196         }
197         if (!*p)
198         {
199             *p = (char *) t->buf;
200             *(*p + t->len) = '\0';  /* ber_octs reserves space for this */
201         }
202     }
203     return 1;
204 }
205 /*
206  * Local variables:
207  * c-basic-offset: 4
208  * indent-tabs-mode: nil
209  * End:
210  * vim: shiftwidth=4 tabstop=8 expandtab
211  */
212