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