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