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-2012 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
28 #include "odr-priv.h"
29
30 static int ber_encinteger(ODR o, Odr_int val);
31 static int ber_decinteger(const unsigned char *buf, Odr_int *val, int max);
32
33 int ber_integer(ODR o, Odr_int *val)
34 {
35     int res;
36
37     switch (o->direction)
38     {
39     case ODR_DECODE:
40         if ((res = ber_decinteger(o->bp, val, odr_max(o))) <= 0)
41         {
42             odr_seterror(o, OPROTO, 50);
43             return 0;
44         }
45         o->bp += res;
46         return 1;
47     case ODR_ENCODE:
48         if ((res = ber_encinteger(o, *val)) < 0)
49             return 0;
50         return 1;
51     case ODR_PRINT:
52         return 1;
53     default:
54         odr_seterror(o, OOTHER, 51);  return 0;
55     }
56 }
57
58 /*
59  * Returns: number of bytes written or -1 for error (out of bounds).
60  */
61 int ber_encinteger(ODR o, Odr_int val)
62 {
63     unsigned long long uval = val;
64     unsigned char tmp[sizeof(uval)];
65     int len;
66     size_t i;
67     for (i = sizeof(uval); i > 0; )
68     {
69         tmp[--i] = uval;
70         uval >>= 8;
71     }
72     for (i = 0; i < sizeof(uval)-1; i++)
73         if (!((tmp[i] == 0 && !(tmp[i+1] & 0x80))
74               ||
75               (tmp[i] == 0xFF && (tmp[i+1] & 0x80))))
76             break;
77     len = sizeof(uval) - i;
78     if (ber_enclen(o, len, 1, 1) != 1)
79         return -1;
80     if (odr_write(o, (unsigned char*) tmp + i, len) < 0)
81         return -1;
82     return 0;
83 }
84
85 /*
86  * Returns: Number of bytes read or 0 if no match, -1 if error.
87  */
88 int ber_decinteger(const unsigned char *buf, Odr_int *val, int max)
89 {
90     unsigned long long uval = 0;
91     int i, len;
92     int res;
93     const unsigned char *b = buf;
94
95     if ((res = ber_declen(b, &len, max)) < 0)
96         return -1;
97     if (len+res > max || len < 0) /* out of bounds or indefinite encoding */
98         return -1;  
99     if (len > (int) sizeof(uval))  /* let's be reasonable, here */
100         return -1;
101     b += res;
102
103     if (*b & 0x80)
104         for (i = 0; i < (int) sizeof(uval) - len; i++)
105             uval = (uval << 8) + 0xFF;
106     for (i = 0; i < len; i++)
107         uval = (uval << 8) + b[i];
108     *val = uval;
109     b += len;
110     return b - buf;
111 }
112 /*
113  * Local variables:
114  * c-basic-offset: 4
115  * c-file-style: "Stroustrup"
116  * indent-tabs-mode: nil
117  * End:
118  * vim: shiftwidth=4 tabstop=8 expandtab
119  */
120