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