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