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