Added skeleton for query charset conversion. Bug #977.
[yaz-moved-to-github.git] / src / odr_cons.c
1 /*
2  * Copyright (C) 1995-2007, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: odr_cons.c,v 1.9 2007-03-19 21:08:13 adam Exp $
6  *
7  */
8
9 /**
10  * \file odr_cons.c
11  * \brief Implements ODR constructed codec.
12  */
13
14 #if HAVE_CONFIG_H
15 #include <config.h>
16 #endif
17
18 #include <assert.h>
19
20 #include "odr-priv.h"
21
22 void odr_setlenlen(ODR o, int len)
23 {
24     o->op->lenlen = len;
25 }
26
27 int odr_constructed_begin(ODR o, void *xxp, int zclass, int tag,
28                           const char *name)
29 {
30     int res;
31     int cons = 1;
32     int lenlen = o->op->lenlen;
33
34     if (o->error)
35         return 0;
36     o->op->lenlen = 1; /* reset lenlen */
37     if (o->op->t_class < 0)
38     {
39         o->op->t_class = zclass;
40         o->op->t_tag = tag;
41     }
42     res = ber_tag(o, xxp, o->op->t_class, o->op->t_tag, &cons, 1, name);
43     if (res < 0)
44         return 0;
45     if (!res || !cons)
46         return 0;
47
48     /* push the odr_constack */
49     if (o->op->stack_top && o->op->stack_top->next)
50     {
51         /* reuse old entry */
52         o->op->stack_top = o->op->stack_top->next;
53     }
54     else if (o->op->stack_top && !o->op->stack_top->next)
55     {
56         /* must allocate new entry (not first) */
57         int sz = 0;
58         struct odr_constack *st;
59         /* check size first */
60         for (st = o->op->stack_top; st; st = st->prev)
61             sz++;
62
63         if (sz >= ODR_MAX_STACK)
64         {
65             odr_seterror(o, OSTACK, 30);
66             return 0;
67         }
68         o->op->stack_top->next = (struct odr_constack *)
69             odr_malloc(o, sizeof(*o->op->stack_top));
70         o->op->stack_top->next->prev = o->op->stack_top;
71         o->op->stack_top->next->next = 0;
72
73         o->op->stack_top = o->op->stack_top->next;
74     }
75     else if (!o->op->stack_top)
76     {
77         /* stack empty */
78         if (!o->op->stack_first)
79         {
80             /* first item must be allocated */
81             o->op->stack_first = (struct odr_constack *)
82                 odr_malloc(o, sizeof(*o->op->stack_top));
83             o->op->stack_first->prev = 0;
84             o->op->stack_first->next = 0;
85         }
86         o->op->stack_top = o->op->stack_first;
87         assert(o->op->stack_top->prev == 0);
88     }
89     o->op->stack_top->lenb = o->bp;
90     o->op->stack_top->len_offset = odr_tell(o);
91     o->op->stack_top->name = name ? name : "?";
92     if (o->direction == ODR_ENCODE)
93     {
94         static unsigned char dummy[sizeof(int)+1];
95
96         o->op->stack_top->lenlen = lenlen;
97
98         if (odr_write(o, dummy, lenlen) < 0)  /* dummy */
99         {
100             ODR_STACK_POP(o);
101             return 0;
102         }
103     }
104     else if (o->direction == ODR_DECODE)
105     {
106         if ((res = ber_declen(o->bp, &o->op->stack_top->len,
107                               odr_max(o))) < 0)
108         {
109             odr_seterror(o, OOTHER, 31);
110             ODR_STACK_POP(o);
111             return 0;
112         }
113         o->op->stack_top->lenlen = res;
114         o->bp += res;
115         if (o->op->stack_top->len > odr_max(o))
116         {
117             odr_seterror(o, OOTHER, 32);
118             ODR_STACK_POP(o);
119             return 0;
120         }
121     }
122     else if (o->direction == ODR_PRINT)
123     {
124         odr_prname(o, name);
125         odr_printf(o, "{\n");
126         o->op->indent++;
127     }
128     else
129     {
130         odr_seterror(o, OOTHER, 33);
131         ODR_STACK_POP(o);
132         return 0;
133     }
134     o->op->stack_top->base = o->bp;
135     o->op->stack_top->base_offset = odr_tell(o);
136     return 1;
137 }
138
139 int odr_constructed_more(ODR o)
140 {
141     if (o->error)
142         return 0;
143     if (ODR_STACK_EMPTY(o))
144         return 0;
145     if (o->op->stack_top->len >= 0)
146         return o->bp - o->op->stack_top->base < o->op->stack_top->len;
147     else
148         return (!(*o->bp == 0 && *(o->bp + 1) == 0));
149 }
150
151 int odr_constructed_end(ODR o)
152 {
153     int res;
154     int pos;
155
156     if (o->error)
157         return 0;
158     if (ODR_STACK_EMPTY(o))
159     {
160         odr_seterror(o, OOTHER, 34);
161         return 0;
162     }
163     switch (o->direction)
164     {
165     case ODR_DECODE:
166         if (o->op->stack_top->len < 0)
167         {
168             if (*o->bp++ == 0 && *(o->bp++) == 0)
169             {
170                 ODR_STACK_POP(o);
171                 return 1;
172             }
173             else
174             {
175                 odr_seterror(o, OOTHER, 35);
176                 return 0;
177             }
178         }
179         else if (o->bp - o->op->stack_top->base !=
180                  o->op->stack_top->len)
181         {
182             odr_seterror(o, OCONLEN, 36);
183             return 0;
184         }
185         ODR_STACK_POP(o);
186         return 1;
187     case ODR_ENCODE:
188         pos = odr_tell(o);
189         odr_seek(o, ODR_S_SET, o->op->stack_top->len_offset);
190         if ((res = ber_enclen(o, pos - o->op->stack_top->base_offset,
191                               o->op->stack_top->lenlen, 1)) < 0)
192         {
193             odr_seterror(o, OLENOV, 37);
194             return 0;
195         }
196         odr_seek(o, ODR_S_END, 0);
197         if (res == 0)   /* indefinite encoding */
198         {
199             if (odr_putc(o, 0) < 0 || odr_putc(o, 0) < 0)
200                 return 0;
201         }
202         ODR_STACK_POP(o);
203         return 1;
204     case ODR_PRINT:
205         ODR_STACK_POP(o);
206         o->op->indent--;
207         odr_prname(o, 0);
208         odr_printf(o, "}\n");
209         return 1;
210     default:
211         odr_seterror(o, OOTHER, 38);
212         return 0;
213     }
214 }
215 /*
216  * Local variables:
217  * c-basic-offset: 4
218  * indent-tabs-mode: nil
219  * End:
220  * vim: shiftwidth=4 tabstop=8 expandtab
221  */
222