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