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