Adjustments.
[yaz-moved-to-github.git] / odr / ber_tag.c
1 /*
2  * Copyright (C) 1994, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: ber_tag.c,v $
7  * Revision 1.6  1995-02-14 11:54:33  quinn
8  * Adjustments.
9  *
10  * Revision 1.5  1995/02/10  18:57:24  quinn
11  * More in the way of error-checking.
12  *
13  * Revision 1.4  1995/02/10  15:55:28  quinn
14  * Bug fixes, mostly.
15  *
16  * Revision 1.3  1995/02/09  15:51:46  quinn
17  * Works better now.
18  *
19  * Revision 1.2  1995/02/07  17:52:59  quinn
20  * A damn mess, but now things work, I think.
21  *
22  * Revision 1.1  1995/02/02  16:21:53  quinn
23  * First kick.
24  *
25  */
26
27 #include <stdio.h>
28 #include <odr.h>
29
30 /* ber_tag
31  * On encoding:
32  *      if  p: write tag. return 1 (success) or -1 (error).
33  *      if !p: return 0.
34  * On decoding:
35  *      if tag && class match up, advance pointer and return 1. set cons.
36  *      else leave pointer unchanged. Return 0.
37  *
38  * Should perhaps be odr_tag?
39 */
40 int ber_tag(ODR o, void *p, int class, int tag, int *constructed)
41 {
42     static int lclass = -1, ltag, br, lcons; /* save t&c rather than
43                                                 decoding twice */
44     int rd;
45     char **pp = p;
46
47     if (o->direction == ODR_DECODE)
48         *pp = 0;
49     o->t_class = -1;
50     if (o->stackp < 0)
51     {
52         o->bp = o->buf;
53         lclass = -1;
54     }
55     switch (o->direction)
56     {
57         case ODR_ENCODE:
58             if (!*pp)
59                 return 0;
60             if ((rd = ber_enctag(o->bp, class, tag, *constructed, o->left))
61                 <=0)
62                 return -1;
63             o->bp += rd;
64             o->left -= rd;
65 #ifdef ODR_DEBUG
66             fprintf(stderr, "\n[class=%d,tag=%d,cons=%d]", class, tag,
67                 *constructed);
68 #endif
69             return 1;
70         case ODR_DECODE:
71             if (o->stackp > -1 && !odr_constructed_more(o))
72                 return 0;
73             if (lclass < 0)
74             {
75                 if ((br = ber_dectag(o->bp, &lclass, &ltag, &lcons)) <= 0)
76                     return 0;
77 #ifdef ODR_DEBUG
78                 fprintf(stderr, "\n[class=%d,tag=%d,cons=%d]", lclass, ltag,
79                     lcons);
80 #endif
81             }
82             if (class == lclass && tag == ltag)
83             {
84                 o->bp += br;
85                 o->left -= br;
86                 *constructed = lcons;
87                 lclass = -1;
88                 return 1;
89             }
90             else
91                 return 0;
92         case ODR_PRINT: return *pp != 0;
93         default: return 0;
94     }
95 }
96
97 /* ber_enctag
98  * BER-encode a class/tag/constructed package (identifier octets). Return
99  * number of bytes encoded, or -1 if out of bounds.
100  */
101 int ber_enctag(unsigned char *buf, int class, int tag, int constructed, int len)
102 {
103     int cons = (constructed ? 1 : 0), n = 0;
104     unsigned char octs[sizeof(int)], *b = buf;
105
106     *b = (class << 6) & 0XC0;
107     *b |= (cons << 5) & 0X20;
108     if (tag <= 30)
109     {
110         *b |= tag & 0X1F;
111         return 1;
112     }
113     else
114     {
115         *(b++) |= 0x1F;
116         do
117         {
118             octs[n++] = tag & 0X7F;
119             tag >>= 7;
120             if (n >= len) /* bounds check */
121                 return -1;
122         }
123         while (tag);
124         while (n--)
125             *(b++) = octs[n] | ((n > 0) << 7);
126         return b - buf;
127     }
128 }
129
130 /* ber_dectag
131  * Decode BER identifier octets. Return number of bytes read or -1 for error.
132  */
133 int ber_dectag(unsigned char *buf, int *class, int *tag, int *constructed)
134 {
135     unsigned char *b = buf;
136
137     *class = *b >> 6;
138     *constructed = (*b >> 5) & 0X01;
139     if ((*tag = *b & 0x1F) <= 30)
140         return 1;
141     b++;
142     *tag = 0;
143     do
144     {
145         *tag <<= 7;
146         *tag |= *b & 0X7F;
147         if (b - buf >= 5) /* Precaution */
148             return -1;
149     }
150     while (*(b++) & 0X80);
151     return b - buf;
152 }