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