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