Reworked odr_set_stream a bit, so that write handler now takes a
[yaz-moved-to-github.git] / src / odr_cons.c
1 /*
2  * Copyright (c) 1995-2004, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Id: odr_cons.c,v 1.3 2004-08-13 07:30:06 adam Exp $
6  *
7  */
8 #if HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include "odr-priv.h"
13
14 void odr_setlenlen(ODR o, int len)
15 {
16     o->lenlen = len;
17 }
18
19 int odr_constructed_begin(ODR o, void *p, int zclass, int tag,
20                           const char *name)
21 {
22     int res;
23     int cons = 1;
24     int lenlen = o->lenlen;
25
26     if (o->error)
27         return 0;
28     o->lenlen = 1; /* reset lenlen */
29     if (o->t_class < 0)
30     {
31         o->t_class = zclass;
32         o->t_tag = tag;
33     }
34     if ((res = ber_tag(o, p, o->t_class, o->t_tag, &cons, 1, name)) < 0)
35         return 0;
36     if (!res || !cons)
37         return 0;
38
39     if (o->op->stackp == ODR_MAX_STACK - 1)
40     {
41         odr_seterror(o, OSTACK, 30);
42         return 0;
43     }
44     o->op->stack[++(o->op->stackp)].lenb = o->bp;
45     o->op->stack[o->op->stackp].len_offset = odr_tell(o);
46     o->op->stack_names[o->op->stackp] = name ? name : "?";
47     o->op->stack_names[o->op->stackp + 1] = 0;
48 #ifdef ODR_DEBUG
49     fprintf(stderr, "[cons_begin(%d)]", o->op->stackp);
50 #endif
51     if (o->direction == ODR_ENCODE)
52     {
53         static unsigned char dummy[sizeof(int)+1];
54
55         o->op->stack[o->op->stackp].lenlen = lenlen;
56
57         if (odr_write(o, dummy, lenlen) < 0)  /* dummy */
58         {
59             o->op->stack_names[o->op->stackp] = 0;
60             --(o->op->stackp);
61             return 0;
62         }
63     }
64     else if (o->direction == ODR_DECODE)
65     {
66         if ((res = ber_declen(o->bp, &o->op->stack[o->op->stackp].len,
67                               odr_max(o))) < 0)
68         {
69             odr_seterror(o, OOTHER, 31);
70             o->op->stack_names[o->op->stackp] = 0;
71             --(o->op->stackp);
72             return 0;
73         }
74         o->op->stack[o->op->stackp].lenlen = res;
75         o->bp += res;
76         if (o->op->stack[o->op->stackp].len > odr_max(o))
77         {
78             odr_seterror(o, OOTHER, 32);
79             o->op->stack_names[o->op->stackp] = 0;
80             --(o->op->stackp);
81             return 0;
82         }
83     }
84     else if (o->direction == ODR_PRINT)
85     {
86         odr_prname(o, name);
87         odr_printf(o, "{\n");
88         o->indent++;
89     }
90     else
91     {
92         odr_seterror(o, OOTHER, 33);
93         o->op->stack_names[o->op->stackp] = 0;
94         --(o->op->stackp);
95         return 0;
96     }
97     o->op->stack[o->op->stackp].base = o->bp;
98     o->op->stack[o->op->stackp].base_offset = odr_tell(o);
99     return 1;
100 }
101
102 int odr_constructed_more(ODR o)
103 {
104     if (o->error)
105         return 0;
106     if (o->op->stackp < 0)
107         return 0;
108     if (o->op->stack[o->op->stackp].len >= 0)
109         return o->bp - o->op->stack[o->op->stackp].base < o->op->stack[o->op->stackp].len;
110     else
111         return (!(*o->bp == 0 && *(o->bp + 1) == 0));
112 }
113
114 int odr_constructed_end(ODR o)
115 {
116     int res;
117     int pos;
118
119     if (o->error)
120         return 0;
121     if (o->op->stackp < 0)
122     {
123         odr_seterror(o, OOTHER, 34);
124         return 0;
125     }
126     o->op->stack_names[o->op->stackp] = 0;
127     switch (o->direction)
128     {
129     case ODR_DECODE:
130         if (o->op->stack[o->op->stackp].len < 0)
131         {
132             if (*o->bp++ == 0 && *(o->bp++) == 0)
133             {
134                     o->op->stackp--;
135                     return 1;
136             }
137             else
138             {
139                 odr_seterror(o, OOTHER, 35);
140                 return 0;
141             }
142         }
143         else if (o->bp - o->op->stack[o->op->stackp].base !=
144                  o->op->stack[o->op->stackp].len)
145         {
146             odr_seterror(o, OCONLEN, 36);
147             return 0;
148         }
149         o->op->stackp--;
150         return 1;
151     case ODR_ENCODE:
152         pos = odr_tell(o);
153         odr_seek(o, ODR_S_SET, o->op->stack[o->op->stackp].len_offset);
154         if ((res = ber_enclen(o, pos - o->op->stack[o->op->stackp].base_offset,
155                               o->op->stack[o->op->stackp].lenlen, 1)) < 0)
156         {
157             odr_seterror(o, OLENOV, 37);
158             return 0;
159         }
160         odr_seek(o, ODR_S_END, 0);
161         if (res == 0)   /* indefinite encoding */
162         {
163 #ifdef ODR_DEBUG
164             fprintf(stderr, "[cons_end(%d): indefinite]", o->op->stackp);
165 #endif
166             if (odr_putc(o, 0) < 0 || odr_putc(o, 0) < 0)
167                 return 0;
168         }
169 #ifdef ODR_DEBUG
170         else
171         {
172             fprintf(stderr, "[cons_end(%d): definite]", o->op->stackp);
173         }
174 #endif
175         o->op->stackp--;
176         return 1;
177     case ODR_PRINT:
178         o->op->stackp--;
179         o->indent--;
180         odr_prname(o, 0);
181         odr_printf(o, "}\n");
182         return 1;
183     default:
184         odr_seterror(o, OOTHER, 38);
185         return 0;
186     }
187 }