index set -> context set
[yaz-moved-to-github.git] / src / ber_int.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_int.c,v 1.1 2003-10-27 12:21:30 adam Exp $
7  */
8 #if HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include <string.h>
13
14 #ifdef WIN32
15 #include <winsock.h>
16 #else
17 #include <sys/types.h>
18 #include <netinet/in.h>
19 #endif
20
21 #include "odr-priv.h"
22
23 static int ber_encinteger(ODR o, int val);
24 static int ber_decinteger(const unsigned char *buf, int *val, int max);
25
26 int ber_integer(ODR o, int *val)
27 {
28     int res;
29
30     switch (o->direction)
31     {
32         case ODR_DECODE:
33             if ((res = ber_decinteger(o->bp, val, odr_max(o))) <= 0)
34             {
35                 odr_seterror(o, OPROTO, 50);
36                 return 0;
37             }
38             o->bp += res;
39             return 1;
40         case ODR_ENCODE:
41             if ((res = ber_encinteger(o, *val)) < 0)
42                 return 0;
43             return 1;
44         case ODR_PRINT: return 1;
45         default: odr_seterror(o, OOTHER, 51);  return 0;
46     }
47 }
48
49 /*
50  * Returns: number of bytes written or -1 for error (out of bounds).
51  */
52 int ber_encinteger(ODR o, int val)
53 {
54     int a, len;
55     union { int i; unsigned char c[sizeof(int)]; } tmp;
56
57     tmp.i = htonl(val);   /* ensure that that we're big-endian */
58     for (a = 0; a < (int) sizeof(int) - 1; a++)  /* skip superfluous octets */
59         if (!((tmp.c[a] == 0 && !(tmp.c[a+1] & 0X80)) ||
60             (tmp.c[a] == 0XFF && (tmp.c[a+1] & 0X80))))
61             break;
62     len = sizeof(int) - a;
63     if (ber_enclen(o, len, 1, 1) != 1)
64         return -1;
65     if (odr_write(o, (unsigned char*) tmp.c + a, len) < 0)
66         return -1;
67 #ifdef ODR_DEBUG
68     fprintf(stderr, "[val=%d]", val);
69 #endif
70     return 0;
71 }
72
73 /*
74  * Returns: Number of bytes read or 0 if no match, -1 if error.
75  */
76 int ber_decinteger(const unsigned char *buf, int *val, int max)
77 {
78     const unsigned char *b = buf;
79     unsigned char fill;
80     int res, len, remains;
81     union { int i; unsigned char c[sizeof(int)]; } tmp;
82
83     if ((res = ber_declen(b, &len, max)) < 0)
84         return -1;
85     if (len+res > max || len < 0) /* out of bounds or indefinite encoding */
86         return -1;  
87     if (len > (int) sizeof(int))  /* let's be reasonable, here */
88         return -1;
89     b+= res;
90
91     remains = sizeof(int) - len;
92     memcpy(tmp.c + remains, b, len);
93     if (*b & 0X80)
94         fill = 0XFF;
95     else
96         fill = 0X00;
97     memset(tmp.c, fill, remains);
98     *val = ntohl(tmp.i);
99
100     b += len;
101 #ifdef ODR_DEBUG
102     fprintf(stderr, "[val=%d]", *val);
103 #endif
104     return b - buf;
105 }