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