Update source headers for 2008. Omit CVS ID keyword subst.
[yaz-moved-to-github.git] / src / ber_int.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2008 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 #else
27 #include <netinet/in.h>
28 #endif
29
30 #include "odr-priv.h"
31
32 static int ber_encinteger(ODR o, int val);
33 static int ber_decinteger(const unsigned char *buf, int *val, int max);
34
35 int ber_integer(ODR o, int *val)
36 {
37     int res;
38
39     switch (o->direction)
40     {
41     case ODR_DECODE:
42         if ((res = ber_decinteger(o->bp, val, odr_max(o))) <= 0)
43         {
44             odr_seterror(o, OPROTO, 50);
45             return 0;
46         }
47         o->bp += res;
48         return 1;
49     case ODR_ENCODE:
50         if ((res = ber_encinteger(o, *val)) < 0)
51             return 0;
52         return 1;
53     case ODR_PRINT:
54         return 1;
55     default:
56         odr_seterror(o, OOTHER, 51);  return 0;
57     }
58 }
59
60 /*
61  * Returns: number of bytes written or -1 for error (out of bounds).
62  */
63 int ber_encinteger(ODR o, int val)
64 {
65     int a, len;
66     union { int i; unsigned char c[sizeof(int)]; } tmp;
67
68     tmp.i = htonl(val);   /* ensure that that we're big-endian */
69     for (a = 0; a < (int) sizeof(int) - 1; a++)  /* skip superfluous octets */
70         if (!((tmp.c[a] == 0 && !(tmp.c[a+1] & 0X80)) ||
71             (tmp.c[a] == 0XFF && (tmp.c[a+1] & 0X80))))
72             break;
73     len = sizeof(int) - a;
74     if (ber_enclen(o, len, 1, 1) != 1)
75         return -1;
76     if (odr_write(o, (unsigned char*) tmp.c + a, len) < 0)
77         return -1;
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     return b - buf;
110 }
111 /*
112  * Local variables:
113  * c-basic-offset: 4
114  * indent-tabs-mode: nil
115  * End:
116  * vim: shiftwidth=4 tabstop=8 expandtab
117  */
118