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