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