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