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