Works better now.
[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.3  1995-02-09 15:51:46  quinn
8  * Works better now.
9  *
10  * Revision 1.2  1995/02/07  17:52:59  quinn
11  * A damn mess, but now things work, I think.
12  *
13  * Revision 1.1  1995/02/02  16:21:53  quinn
14  * First kick.
15  *
16  */
17
18 #include <stdio.h>
19 #include <odr.h>
20
21 /* ber_tag
22  * On encoding:
23  *      if  p: write tag. return 1 (success) or -1 (error).
24  *      if !p: return 0.
25  * On decoding:
26  *      if tag && class match up, advance pointer and return 1. set cons.
27  *      else leave pointer unchanged. Return 0.
28 */
29 int ber_tag(ODR o, const void *p, int class, int tag, int *constructed)
30 {
31     static int lclass = -1, ltag, br, lcons; /* save t&c rather than
32                                                 decoding twice */
33     int rd;
34
35     o->t_class = -1;
36     if (o->buf == o->bp)   /* This is insurance. It shouldn't be necessary */
37         lclass = -1;
38     switch (o->direction)
39     {
40         case ODR_ENCODE:
41             if (!p)
42                 return 0;
43             if ((rd = ber_enctag(o->bp, class, tag, *constructed, o->left))
44                 <=0)
45                 return -1;
46             o->bp += rd;
47             o->left -= rd;
48 #ifdef ODR_DEBUG
49             fprintf(stderr, "\n[class=%d,tag=%d,cons=%d]", class, tag,
50                 *constructed);
51 #endif
52             return 1;
53         case ODR_DECODE:
54             if (lclass < 0)
55             {
56                 if ((br = ber_dectag(o->bp, &lclass, &ltag, &lcons)) <= 0)
57                     return -1;
58 #ifdef ODR_DEBUG
59                 fprintf(stderr, "\n[class=%d,tag=%d,cons=%d]", lclass, ltag,
60                     lcons);
61 #endif
62             }
63             if (class == lclass && tag == ltag)
64             {
65                 o->bp += br;
66                 o->left -= br;
67                 *constructed = lcons;
68                 lclass = -1;
69                 return 1;
70             }
71             else
72                 return 0;
73         case ODR_PRINT: return p != 0;
74         default: return 0;
75     }
76 }
77
78 /* ber_enctag
79  * BER-encode a class/tag/constructed package (identifier octets). Return
80  * number of bytes encoded, or -1 if out of bounds.
81  */
82 int ber_enctag(unsigned char *buf, int class, int tag, int constructed, int len)
83 {
84     int cons = (constructed ? 1 : 0), n = 0;
85     unsigned char octs[sizeof(int)], *b = buf;
86
87     *b = (class << 6) & 0XC0;
88     *b |= (cons << 5) & 0X20;
89     if (tag <= 30)
90     {
91         *b |= tag & 0X1F;
92         return 1;
93     }
94     else
95     {
96         *(b++) |= 0x1F;
97         do
98         {
99             octs[n++] = tag & 0X7F;
100             tag >>= 7;
101             if (n >= len) /* bounds check */
102                 return -1;
103         }
104         while (tag);
105         while (n--)
106             *(b++) = octs[n] | ((n > 0) << 7);
107         return b - buf;
108     }
109 }
110
111 /* ber_dectag
112  * Decode BER identifier octets. Return number of bytes read or -1 for error.
113  */
114 int ber_dectag(unsigned char *buf, int *class, int *tag, int *constructed)
115 {
116     unsigned char *b = buf;
117
118     *class = *b >> 6;
119     *constructed = (*b >> 5) & 0X01;
120     if ((*tag = *b & 0x1F) <= 30)
121         return 1;
122     b++;
123     *tag = 0;
124     do
125     {
126         *tag <<= 7;
127         *tag |= *b & 0X7F;
128         if (b - buf >= 5) /* Precaution */
129             return -1;
130     }
131     while (*(b++) & 0X80);
132     return b - buf;
133 }