cdf4dd96bd8c4fd9641d1a5e344ad304bb55e2d4
[yaz-moved-to-github.git] / src / ber_tag.c
1 /*
2  * Copyright (C) 1995-2007, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: ber_tag.c,v 1.7 2007-01-03 08:42:15 adam Exp $
6  */
7
8 /** 
9  * \file ber_tag.c
10  * \brief Implements BER tags encoding and decoding
11  *
12  * This source file implements BER encoding and decoding of
13  * the tags.
14  */
15 #if HAVE_CONFIG_H
16 #include <config.h>
17 #endif
18
19 #include <stdio.h>
20 #include "odr-priv.h"
21
22 /**
23  * \brief Encode/decode BER tags
24  *
25  * On encoding:
26  * \verbatim
27  *      if  p: write tag. return 1 (success) or -1 (error).
28  *      if !p: return 0.
29  * \endverbatim
30  * On decoding:
31  * \verbatim
32  *      if tag && zclass match up, advance pointer and return 1. set cons.
33  *      else leave pointer unchanged. Return 0.
34  * \endverbatim
35  */
36 int ber_tag(ODR o, void *p, int zclass, int tag, int *constructed, int opt,
37             const char *name)
38 {
39     struct Odr_ber_tag *odr_ber_tag = &o->op->odr_ber_tag;
40     int rd;
41     char **pp = (char **)p;
42
43     if (o->direction == ODR_DECODE)
44         *pp = 0;
45     o->t_class = -1;
46     if (ODR_STACK_EMPTY(o))
47     {
48         odr_seek(o, ODR_S_SET, 0);
49         o->top = 0;
50         o->bp = o->buf;
51         odr_ber_tag->lclass = -1;
52     }
53     switch (o->direction)
54     {
55     case ODR_ENCODE:
56         if (!*pp)
57         {
58             if (!opt)
59             {
60                 odr_seterror(o, OREQUIRED, 24);
61                 odr_setelement (o, name);
62             }
63             return 0;
64         }
65         if ((rd = ber_enctag(o, zclass, tag, *constructed)) < 0)
66             return -1;
67         return 1;
68     case ODR_DECODE:
69         if (ODR_STACK_NOT_EMPTY(o) && !odr_constructed_more(o))
70         {
71             if (!opt)
72             {
73                 odr_seterror(o, OREQUIRED, 25);
74                 odr_setelement(o, name);
75             }
76             return 0;
77         }
78         if (odr_ber_tag->lclass < 0)
79         {
80             if ((odr_ber_tag->br =
81                  ber_dectag(o->bp, &odr_ber_tag->lclass,
82                             &odr_ber_tag->ltag, &odr_ber_tag->lcons,
83                             odr_max(o))) <= 0)
84             {
85                 odr_seterror(o, OPROTO, 26);
86                 odr_setelement(o, name);
87                 return 0;
88             }
89         }
90         if (zclass == odr_ber_tag->lclass && tag == odr_ber_tag->ltag)
91         {
92             o->bp += odr_ber_tag->br;
93             *constructed = odr_ber_tag->lcons;
94             odr_ber_tag->lclass = -1;
95             return 1;
96         }
97         else
98         {
99             if (!opt)
100             {
101                 odr_seterror(o, OREQUIRED, 27);
102                 odr_setelement(o, name);
103             }
104             return 0;
105         }
106     case ODR_PRINT:
107         if (!*pp && !opt)
108         {
109             odr_seterror(o,OREQUIRED, 28);
110             odr_setelement(o, name);
111         }
112         return *pp != 0;
113     default:
114         odr_seterror(o, OOTHER, 29);
115         odr_setelement(o, name);
116         return 0;
117     }
118 }
119
120 /**
121  * \brief BER-encode a zclass/tag/constructed package (identifier octets).
122  *
123  * Return number of bytes encoded, or -1 if out of bounds.
124  */
125 int ber_enctag(ODR o, int zclass, int tag, int constructed)
126 {
127     int cons = (constructed ? 1 : 0), n = 0;
128     unsigned char octs[sizeof(int)], b;
129
130     b = (zclass << 6) & 0XC0;
131     b |= (cons << 5) & 0X20;
132     if (tag <= 30)
133     {
134         b |= tag & 0X1F;
135         if (odr_putc(o, b) < 0)
136             return -1;
137         return 1;
138     }
139     else
140     {
141         b |= 0X1F;
142         if (odr_putc(o, b) < 0)
143             return -1;
144         do
145         {
146             octs[n++] = tag & 0X7F;
147             tag >>= 7;
148         }
149         while (tag);
150         while (n--)
151         {
152             unsigned char oo;
153
154             oo = octs[n] | ((n > 0) << 7);
155             if (odr_putc(o, oo) < 0)
156                 return -1;
157         }
158         return 0;
159     }
160 }
161
162 /** 
163  * \brief Decodes BER identifier octets.
164  *
165  * Returns number of bytes read or -1 for error.
166  */
167 int ber_dectag(const unsigned char *b, int *zclass, int *tag,
168                int *constructed, int max)
169 {
170     int l = 1;
171
172     if (l > max)
173         return -1;
174
175     *zclass = *b >> 6;
176     *constructed = (*b >> 5) & 0X01;
177     if ((*tag = *b & 0x1F) <= 30)
178         return 1;
179     *tag = 0;
180     do
181     {
182         if (l >= max)
183             return -1;
184         *tag <<= 7;
185         *tag |= b[l] & 0X7F;
186     }
187     while (b[l++] & 0X80);
188     return l;
189 }
190 /*
191  * Local variables:
192  * c-basic-offset: 4
193  * indent-tabs-mode: nil
194  * End:
195  * vim: shiftwidth=4 tabstop=8 expandtab
196  */
197