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