No more manifest files
[yaz-moved-to-github.git] / src / ber_len.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
5
6 /**
7  * \file ber_len.c
8  * \brief Implements BER length octet encoding and decoding
9  *
10  * This source file implements BER encoding and decoding of
11  * the length octets.
12  */
13
14 #if HAVE_CONFIG_H
15 #include <config.h>
16 #endif
17
18 #include <stdio.h>
19 #include "odr-priv.h"
20
21 /**
22  * ber_enclen:
23  * Encode BER length octets. If exact, lenlen is the exact desired
24  * encoding size, else, lenlen is the max available space. Len < 0 =
25  * Indefinite encoding.
26  * Returns: >0   success, number of bytes encoded.
27  * Returns: =0   success, indefinite start-marker set. 1 byte encoded.
28  * Returns: -1   failure, out of bounds.
29  */
30 int ber_enclen(ODR o, int len, int lenlen, int exact)
31 {
32     unsigned char octs[sizeof(int)];
33     int n = 0;
34     int lenpos, end;
35
36     if (len < 0)      /* Indefinite */
37     {
38         if (odr_putc(o, 0x80) < 0)
39             return 0;
40         return 0;
41     }
42     if (len <= 127 && (lenlen == 1 || !exact)) /* definite short form */
43     {
44         if (odr_putc(o, (unsigned char) len) < 0)
45             return 0;
46         return 1;
47     }
48     if (lenlen == 1)
49     {
50         if (odr_putc(o, 0x80) < 0)
51             return 0;
52         return 0;
53     }
54     /* definite long form */
55     do
56     {
57         octs[n++] = len;
58         len >>= 8;
59     }
60     while (len);
61     if (n >= lenlen)
62         return -1;
63     lenpos = odr_tell(o); /* remember length-of-length position */
64     if (odr_putc(o, 0) < 0)  /* dummy */
65         return 0;
66     if (exact)
67         while (n < --lenlen)        /* pad length octets */
68             if (odr_putc(o, 0) < 0)
69                 return 0;
70     while (n--)
71         if (odr_putc(o, octs[n]) < 0)
72             return 0;
73     /* set length of length */
74     end = odr_tell(o);
75     odr_seek(o, ODR_S_SET, lenpos);
76     if (odr_putc(o, (end - lenpos - 1) | 0X80) < 0)
77         return 0;
78     odr_seek(o, ODR_S_END, 0);
79     return odr_tell(o) - lenpos;
80 }
81
82 /**
83  * ber_declen:
84  * Decode BER length octets. Returns
85  *  > 0  : number of bytes read
86  *   -1  : not enough room to read bytes within max bytes
87  *   -2  : other error
88  *
89  * After return:
90  * len = -1   indefinite length.
91  * len >= 0   definite length
92  */
93 int ber_declen(const char *buf, int *len, int max)
94 {
95     const unsigned char *b = (const unsigned char *) buf;
96     int n;
97
98     if (max < 1)
99         return -1;
100     if (*b == 0X80)     /* Indefinite */
101     {
102         *len = -1;
103         return 1;
104     }
105     if (!(*b & 0X80))   /* Definite short form */
106     {
107         *len = (int) *b;
108         return 1;
109     }
110     if (*b == 0XFF)     /* reserved value */
111         return -2;
112     /* indefinite long form */
113     n = *b & 0X7F;
114     if (n >= max)
115         return -1;
116     *len = 0;
117     b++;
118     while (--n >= 0)
119     {
120         *len <<= 8;
121         *len |= *(b++);
122     }
123     if (*len < 0)
124         return -2;
125     return ((const char *) b - buf);
126 }
127 /*
128  * Local variables:
129  * c-basic-offset: 4
130  * c-file-style: "Stroustrup"
131  * indent-tabs-mode: nil
132  * End:
133  * vim: shiftwidth=4 tabstop=8 expandtab
134  */
135