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