Added body-of-text to BIB-1 ANY and the WAIS profile
[yaz-moved-to-github.git] / odr / ber_tag.c
1 /*
2  * Copyright (c) 1995, Index Data
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: ber_tag.c,v $
7  * Revision 1.13  1995-09-29 17:12:21  quinn
8  * Smallish
9  *
10  * Revision 1.12  1995/09/27  15:02:57  quinn
11  * Modified function heads & prototypes.
12  *
13  * Revision 1.11  1995/05/16  08:50:48  quinn
14  * License, documentation, and memory fixes
15  *
16  * Revision 1.10  1995/04/18  08:15:18  quinn
17  * Added dynamic memory allocation on encoding (whew). Code is now somewhat
18  * neater. We'll make the same change for decoding one day.
19  *
20  * Revision 1.9  1995/03/15  08:37:18  quinn
21  * Fixed protocol bugs.
22  *
23  * Revision 1.8  1995/03/10  11:44:40  quinn
24  * Fixed serious stack-bug in odr_cons_begin
25  *
26  * Revision 1.7  1995/03/08  12:12:13  quinn
27  * Added better error checking.
28  *
29  * Revision 1.6  1995/02/14  11:54:33  quinn
30  * Adjustments.
31  *
32  * Revision 1.5  1995/02/10  18:57:24  quinn
33  * More in the way of error-checking.
34  *
35  * Revision 1.4  1995/02/10  15:55:28  quinn
36  * Bug fixes, mostly.
37  *
38  * Revision 1.3  1995/02/09  15:51:46  quinn
39  * Works better now.
40  *
41  * Revision 1.2  1995/02/07  17:52:59  quinn
42  * A damn mess, but now things work, I think.
43  *
44  * Revision 1.1  1995/02/02  16:21:53  quinn
45  * First kick.
46  *
47  */
48
49 #include <stdio.h>
50 #include <odr.h>
51
52 /* ber_tag
53  * On encoding:
54  *      if  p: write tag. return 1 (success) or -1 (error).
55  *      if !p: return 0.
56  * On decoding:
57  *      if tag && class match up, advance pointer and return 1. set cons.
58  *      else leave pointer unchanged. Return 0.
59  *
60  * Should perhaps be odr_tag?
61 */
62 int ber_tag(ODR o, void *p, int class, int tag, int *constructed, int opt)
63 {
64     static int lclass = -1, ltag, br, lcons; /* save t&c rather than
65                                                 decoding twice */
66     int rd;
67     char **pp = p;
68
69     if (o->direction == ODR_DECODE)
70         *pp = 0;
71     o->t_class = -1;
72     if (o->stackp < 0)
73     {
74         odr_seek(o, ODR_S_SET, 0);
75         o->ecb.top = 0;
76         o->bp = o->buf;
77         lclass = -1;
78     }
79     switch (o->direction)
80     {
81         case ODR_ENCODE:
82             if (!*pp)
83             {
84                 if (!opt)
85                     o->error = OREQUIRED;
86                 return 0;
87             }
88             if ((rd = ber_enctag(o, class, tag, *constructed)) < 0)
89                 return -1;
90 #ifdef ODR_DEBUG
91             fprintf(stderr, "\n[class=%d,tag=%d,cons=%d,stackp=%d]", class, tag,
92                 *constructed, o->stackp);
93 #endif
94             return 1;
95         case ODR_DECODE:
96             if (o->stackp > -1 && !odr_constructed_more(o))
97             {
98                 if (!opt)
99                     o->error = OREQUIRED;
100                 return 0;
101             }
102             if (lclass < 0)
103             {
104                 if ((br = ber_dectag(o->bp, &lclass, &ltag, &lcons)) <= 0)
105                 {
106                     o->error = OPROTO;
107                     return 0;
108                 }
109 #ifdef ODR_DEBUG
110                 fprintf(stderr, "\n[class=%d,tag=%d,cons=%d,stackp=%d]", lclass, ltag,
111                     lcons, o->stackp);
112 #endif
113             }
114             if (class == lclass && tag == ltag)
115             {
116                 o->bp += br;
117                 o->left -= br;
118                 *constructed = lcons;
119                 lclass = -1;
120                 return 1;
121             }
122             else
123             {
124                 if (!opt)
125                     o->error = OREQUIRED;
126                 return 0;
127             }
128         case ODR_PRINT:
129                 if (!*pp && !opt)
130                     o->error = OREQUIRED;
131                 return *pp != 0;
132         default: o->error = OOTHER; return 0;
133     }
134 }
135
136 /* ber_enctag
137  * BER-encode a class/tag/constructed package (identifier octets). Return
138  * number of bytes encoded, or -1 if out of bounds.
139  */
140 int ber_enctag(ODR o, int class, int tag, int constructed)
141 {
142     int cons = (constructed ? 1 : 0), n = 0;
143     unsigned char octs[sizeof(int)], b;
144
145     b = (class << 6) & 0XC0;
146     b |= (cons << 5) & 0X20;
147     if (tag <= 30)
148     {
149         b |= tag & 0X1F;
150         if (odr_putc(o, b) < 0)
151             return -1;
152         return 1;
153     }
154     else
155     {
156         b |= 0X1F;
157         if (odr_putc(o, b) < 0)
158             return -1;
159         do
160         {
161             octs[n++] = tag & 0X7F;
162             tag >>= 7;
163         }
164         while (tag);
165         while (n--)
166         {
167             unsigned char oo;
168
169             oo = octs[n] | ((n > 0) << 7);
170             if (odr_putc(o, oo) < 0)
171                 return -1;
172         }
173         return 0;
174     }
175 }
176
177 /* ber_dectag
178  * Decode BER identifier octets. Return number of bytes read or -1 for error.
179  */
180 int ber_dectag(unsigned char *buf, int *class, int *tag, int *constructed)
181 {
182     unsigned char *b = buf;
183
184     *class = *b >> 6;
185     *constructed = (*b >> 5) & 0X01;
186     if ((*tag = *b & 0x1F) <= 30)
187         return 1;
188     b++;
189     *tag = 0;
190     do
191     {
192         *tag <<= 7;
193         *tag |= *b & 0X7F;
194         if (b - buf >= 5) /* Precaution */
195             return -1;
196     }
197     while (*(b++) & 0X80);
198     return b - buf;
199 }