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