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