b6f76448e6727c0a4204b1fec040e5fa69638048
[yaz-moved-to-github.git] / src / ber_tag.c
1 /*
2  * Copyright (C) 1995-2005, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: ber_tag.c,v 1.4 2005-01-15 19:47:11 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 /* ber_tag
23  * On encoding:
24  *      if  p: write tag. return 1 (success) or -1 (error).
25  *      if !p: return 0.
26  * On decoding:
27  *      if tag && zclass match up, advance pointer and return 1. set cons.
28  *      else leave pointer unchanged. Return 0.
29  *
30  * Should perhaps be odr_tag?
31  */
32 int ber_tag(ODR o, void *p, int zclass, int tag, int *constructed, int opt,
33             const char *name)
34 {
35     struct Odr_ber_tag *odr_ber_tag = &o->op->odr_ber_tag;
36     int rd;
37     char **pp = (char **)p;
38
39     if (o->direction == ODR_DECODE)
40         *pp = 0;
41     o->t_class = -1;
42     if (o->op->stackp < 0)
43     {
44         odr_seek(o, ODR_S_SET, 0);
45         o->top = 0;
46         o->bp = o->buf;
47         odr_ber_tag->lclass = -1;
48     }
49     switch (o->direction)
50     {
51     case ODR_ENCODE:
52         if (!*pp)
53         {
54             if (!opt)
55             {
56                 odr_seterror(o, OREQUIRED, 24);
57                 odr_setelement (o, name);
58             }
59             return 0;
60         }
61         if ((rd = ber_enctag(o, zclass, tag, *constructed)) < 0)
62             return -1;
63 #ifdef ODR_DEBUG
64         fprintf(stderr, "\n[class=%d,tag=%d,cons=%d,stackp=%d]", zclass, tag,
65                 *constructed, o->op->stackp);
66 #endif
67         return 1;
68         
69     case ODR_DECODE:
70         if (o->op->stackp > -1 && !odr_constructed_more(o))
71         {
72             if (!opt)
73             {
74                 odr_seterror(o, OREQUIRED, 25);
75                 odr_setelement(o, name);
76             }
77             return 0;
78         }
79         if (odr_ber_tag->lclass < 0)
80         {
81             if ((odr_ber_tag->br =
82                  ber_dectag(o->bp, &odr_ber_tag->lclass,
83                             &odr_ber_tag->ltag, &odr_ber_tag->lcons,
84                             odr_max(o))) <= 0)
85             {
86                 odr_seterror(o, OPROTO, 26);
87                 odr_setelement(o, name);
88                 return 0;
89             }
90 #ifdef ODR_DEBUG
91             fprintf(stderr,
92                     "\n[class=%d,tag=%d,cons=%d,stackp=%d]",
93                     odr_ber_tag->lclass, odr_ber_tag->ltag,
94                     odr_ber_tag->lcons, o->op->stackp);
95 #endif
96         }
97         if (zclass == odr_ber_tag->lclass && tag == odr_ber_tag->ltag)
98         {
99             o->bp += odr_ber_tag->br;
100             *constructed = odr_ber_tag->lcons;
101             odr_ber_tag->lclass = -1;
102             return 1;
103         }
104         else
105         {
106             if (!opt)
107             {
108                 odr_seterror(o, OREQUIRED, 27);
109                 odr_setelement(o, name);
110             }
111             return 0;
112         }
113     case ODR_PRINT:
114         if (!*pp && !opt)
115         {
116             odr_seterror(o,OREQUIRED, 28);
117             odr_setelement(o, name);
118         }
119         return *pp != 0;
120     default:
121         odr_seterror(o, OOTHER, 29);
122         odr_setelement(o, name);
123         return 0;
124     }
125 }
126
127 /* ber_enctag
128  * BER-encode a zclass/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 zclass, int tag, int constructed)
132 {
133     int cons = (constructed ? 1 : 0), n = 0;
134     unsigned char octs[sizeof(int)], b;
135
136     b = (zclass << 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(const unsigned char *b, int *zclass, int *tag,
172                int *constructed, int max)
173 {
174     int l = 1;
175
176     if (l > max)
177         return -1;
178
179     *zclass = *b >> 6;
180     *constructed = (*b >> 5) & 0X01;
181     if ((*tag = *b & 0x1F) <= 30)
182         return 1;
183     *tag = 0;
184     do
185     {
186         if (l >= max)
187             return -1;
188         *tag <<= 7;
189         *tag |= b[l] & 0X7F;
190     }
191     while (b[l++] & 0X80);
192     return l;
193 }