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