ee705635386130f10fc2fe495c9b6b76d207f4b8
[yaz-moved-to-github.git] / odr / ber_len.c
1 #include <stdio.h>
2 #include <odr.h>
3
4 /*
5  * Encode BER length octets. If exact, lenlen is the exact desired
6  * encoding size, else, lenlen is the max available space. Len < 0 =
7  * Indefinite encoding.
8  * Returns: >0   success, number of bytes encoded.
9  * Returns: =0   success, indefinite start-marker set. 1 byte encoded.
10  * Returns: -1   failure, out of bounds.
11  */
12 int ber_enclen(ODR o, int len, int lenlen, int exact)
13 {
14     unsigned char octs[sizeof(int)];
15     int n = 0;
16     int lenpos, end;
17
18 #ifdef ODR_DEBUG
19     fprintf(stderr, "[len=%d]", len);
20 #endif
21     if (len < 0)      /* Indefinite */
22     {
23         if (odr_putc(o, 0x80) < 0)
24             return 0;
25 #ifdef ODR_DEBUG
26         fprintf(stderr, "[indefinite]");
27 #endif
28         return 0;
29     }
30     if (len <= 127 && (lenlen == 1 || !exact)) /* definite short form */
31     {
32         if (odr_putc(o, (unsigned char) len) < 0)
33             return 0;
34         return 1;
35     }
36     if (lenlen == 1)
37     {
38         if (odr_putc(o, 0x80) < 0)
39             return 0;
40         return 0;
41     }
42     /* definite long form */
43     do
44     {
45         octs[n++] = len;
46         len >>= 8;
47     }
48     while (len);
49     if (n >= lenlen)
50         return -1;
51     lenpos = odr_tell(o); /* remember length-of-length position */
52     if (odr_putc(o, 0) < 0)  /* dummy */
53         return 0;
54     if (exact)
55         while (n < --lenlen)        /* pad length octets */
56             if (odr_putc(o, 0) < 0)
57                 return 0;
58     while (n--)
59         if (odr_putc(o, octs[n]) < 0)
60             return 0;
61     /* set length of length */
62     end = odr_tell(o);
63     odr_seek(o, ODR_S_SET, lenpos);
64     if (odr_putc(o, (end - lenpos - 1) | 0X80) < 0)
65         return 0;
66     odr_seek(o, ODR_S_END, 0);
67     return odr_tell(o) - lenpos;
68 }
69
70 /*
71  * Decode BER length octets. Returns number of bytes read or -1 for error.
72  * After return:
73  * len = -1   indefinite.
74  * len >= 0    Length.
75  */
76 int ber_declen(unsigned char *buf, int *len)
77 {
78     unsigned char *b = buf;
79     int n;
80
81     if (*b == 0X80)     /* Indefinite */
82     {
83         *len = -1;
84 #ifdef ODR_DEBUG
85         fprintf(stderr, "[len=%d]", *len);
86 #endif
87         return 1;
88     }
89     if (!(*b & 0X80))   /* Definite short form */
90     {
91         *len = (int) *b;
92 #ifdef ODR_DEBUG
93         fprintf(stderr, "[len=%d]", *len);
94 #endif
95         return 1;
96     }
97     if (*b == 0XFF)     /* reserved value */
98         return -1;
99     /* indefinite long form */ 
100     n = *b & 0X7F;
101     *len = 0;
102     b++;
103     while (n--)
104     {
105         *len <<= 8;
106         *len |= *(b++);
107     }
108 #ifdef ODR_DEBUG
109     fprintf(stderr, "[len=%d]", *len);
110 #endif
111     return (b - buf);
112 }