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