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