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