*** empty log message ***
[yaz-moved-to-github.git] / odr / ber_len.c
1 /*
2  * Copyright (C) 1995, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: ber_len.c,v $
7  * Revision 1.4  1995-05-16 08:50:45  quinn
8  * License, documentation, and memory fixes
9  *
10  *
11  */
12
13 #include <stdio.h>
14 #include <odr.h>
15
16 /*
17  * Encode BER length octets. If exact, lenlen is the exact desired
18  * encoding size, else, lenlen is the max available space. Len < 0 =
19  * Indefinite encoding.
20  * Returns: >0   success, number of bytes encoded.
21  * Returns: =0   success, indefinite start-marker set. 1 byte encoded.
22  * Returns: -1   failure, out of bounds.
23  */
24 int ber_enclen(ODR o, int len, int lenlen, int exact)
25 {
26     unsigned char octs[sizeof(int)];
27     int n = 0;
28     int lenpos, end;
29
30 #ifdef ODR_DEBUG
31     fprintf(stderr, "[len=%d]", len);
32 #endif
33     if (len < 0)      /* Indefinite */
34     {
35         if (odr_putc(o, 0x80) < 0)
36             return 0;
37 #ifdef ODR_DEBUG
38         fprintf(stderr, "[indefinite]");
39 #endif
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  * Decode BER length octets. Returns number of bytes read or -1 for error.
84  * After return:
85  * len = -1   indefinite.
86  * len >= 0    Length.
87  */
88 int ber_declen(unsigned char *buf, int *len)
89 {
90     unsigned char *b = buf;
91     int n;
92
93     if (*b == 0X80)     /* Indefinite */
94     {
95         *len = -1;
96 #ifdef ODR_DEBUG
97         fprintf(stderr, "[len=%d]", *len);
98 #endif
99         return 1;
100     }
101     if (!(*b & 0X80))   /* Definite short form */
102     {
103         *len = (int) *b;
104 #ifdef ODR_DEBUG
105         fprintf(stderr, "[len=%d]", *len);
106 #endif
107         return 1;
108     }
109     if (*b == 0XFF)     /* reserved value */
110         return -1;
111     /* indefinite long form */ 
112     n = *b & 0X7F;
113     *len = 0;
114     b++;
115     while (n--)
116     {
117         *len <<= 8;
118         *len |= *(b++);
119     }
120 #ifdef ODR_DEBUG
121     fprintf(stderr, "[len=%d]", *len);
122 #endif
123     return (b - buf);
124 }