SRW, CQL, 2003
[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.24 2003-01-06 08:20:27 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                 o->error = OREQUIRED;
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                 o->error = OREQUIRED;
63             return 0;
64         }
65         if (odr_ber_tag->lclass < 0)
66         {
67             if ((odr_ber_tag->br = ber_dectag(o->bp, &odr_ber_tag->lclass,
68                                               &odr_ber_tag->ltag, &odr_ber_tag->lcons)) <= 0)
69             {
70                 o->error = OPROTO;
71                 return 0;
72             }
73 #ifdef ODR_DEBUG
74             fprintf(stderr,
75                     "\n[class=%d,tag=%d,cons=%d,stackp=%d]",
76                     odr_ber_tag->lclass, odr_ber_tag->ltag,
77                     odr_ber_tag->lcons, o->stackp);
78 #endif
79         }
80         if (zclass == odr_ber_tag->lclass && tag == odr_ber_tag->ltag)
81         {
82             o->bp += odr_ber_tag->br;
83             *constructed = odr_ber_tag->lcons;
84             odr_ber_tag->lclass = -1;
85             return 1;
86         }
87         else
88         {
89             if (!opt)
90                 o->error = OREQUIRED;
91             return 0;
92         }
93     case ODR_PRINT:
94         if (!*pp && !opt)
95             o->error = OREQUIRED;
96         return *pp != 0;
97     default:
98         o->error = OOTHER;
99         return 0;
100     }
101 }
102
103 /* ber_enctag
104  * BER-encode a zclass/tag/constructed package (identifier octets). Return
105  * number of bytes encoded, or -1 if out of bounds.
106  */
107 int ber_enctag(ODR o, int zclass, int tag, int constructed)
108 {
109     int cons = (constructed ? 1 : 0), n = 0;
110     unsigned char octs[sizeof(int)], b;
111
112     b = (zclass << 6) & 0XC0;
113     b |= (cons << 5) & 0X20;
114     if (tag <= 30)
115     {
116         b |= tag & 0X1F;
117         if (odr_putc(o, b) < 0)
118             return -1;
119         return 1;
120     }
121     else
122     {
123         b |= 0X1F;
124         if (odr_putc(o, b) < 0)
125             return -1;
126         do
127         {
128             octs[n++] = tag & 0X7F;
129             tag >>= 7;
130         }
131         while (tag);
132         while (n--)
133         {
134             unsigned char oo;
135
136             oo = octs[n] | ((n > 0) << 7);
137             if (odr_putc(o, oo) < 0)
138                 return -1;
139         }
140         return 0;
141     }
142 }
143
144 /* ber_dectag
145  * Decode BER identifier octets. Return number of bytes read or -1 for error.
146  */
147 int ber_dectag(const unsigned char *buf, int *zclass, int *tag, int *constructed)
148 {
149     const unsigned char *b = buf;
150
151     *zclass = *b >> 6;
152     *constructed = (*b >> 5) & 0X01;
153     if ((*tag = *b & 0x1F) <= 30)
154         return 1;
155     b++;
156     *tag = 0;
157     do
158     {
159         *tag <<= 7;
160         *tag |= *b & 0X7F;
161         if (b - buf >= 5) /* Precaution */
162             return -1;
163     }
164     while (*(b++) & 0X80);
165     return b - buf;
166 }