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