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