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