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