Works better now.
[yaz-moved-to-github.git] / odr / ber_int.c
1 /*
2  * Copyright (C) 1994, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: ber_int.c,v $
7  * Revision 1.3  1995-02-09 15:51:46  quinn
8  * Works better now.
9  *
10  * Revision 1.2  1995/02/07  17:52:58  quinn
11  * A damn mess, but now things work, I think.
12  *
13  * Revision 1.1  1995/02/02  16:21:52  quinn
14  * First kick.
15  *
16  */
17
18 #include <odr.h>
19 #include <netinet/in.h>
20 #include <string.h>
21
22 static int ber_encinteger(unsigned char *buf, int val, int maxlen);
23 static int ber_decinteger(unsigned char *buf, int *val);
24
25 int ber_integer(ODR o, int *val)
26 {
27     int res;
28
29     switch (o->direction)
30     {
31         case ODR_DECODE:
32             if ((res = ber_decinteger(o->bp, val)) <= 0)
33                 return 0;
34             o->bp += res;
35             o->left -= res;
36             return 1;
37         case ODR_ENCODE:
38             if ((res = ber_encinteger(o->bp, *val, o->left)) <= 0)
39                 return 0;
40             o->bp += res;
41             o->left -= res;
42             return 1;
43         case ODR_PRINT: return 1;
44         default:  return 0;
45     }
46 }
47
48 /*
49  * Returns: number of bytes written or -1 for error (out of bounds).
50  */
51 int ber_encinteger(unsigned char *buf, int val, int maxlen)
52 {
53     unsigned char *b = buf, *lenpos;
54     int a, len;
55     union { int i; unsigned char c[sizeof(int)]; } tmp;
56
57     lenpos = b;
58     maxlen--;
59     b++;
60
61     tmp.i = htonl(val);   /* ensure that that we're big-endian */
62     for (a = 0; a < 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     if ((len = sizeof(int) - a) > maxlen)
67         return -1;
68     memcpy(b, tmp.c + a, len);
69     b += len;
70     if (ber_enclen(lenpos, len, 1, 1) != 1)
71         return -1;
72 #ifdef ODR_DEBUG
73     fprintf(stderr, "[val=%d]", val);
74 #endif
75     return b - buf;
76 }
77
78 /*
79  * Returns: Number of bytes read or 0 if no match, -1 if error.
80  */
81 int ber_decinteger(unsigned char *buf, int *val)
82 {
83     unsigned char *b = buf, fill;
84     int res, len, remains;
85     union { int i; unsigned char c[sizeof(int)]; } tmp;
86
87     if ((res = ber_declen(b, &len)) < 0)
88         return -1;
89     if (len > sizeof(int))    /* let's be reasonable, here */
90         return -1;
91     b+= res;
92
93     remains = sizeof(int) - len;
94     memcpy(tmp.c + remains, b, len);
95     if (*b & 0X80)
96         fill = 0XFF;
97     else
98         fill = 0X00;
99     memset(tmp.c, fill, remains);
100     *val = ntohl(tmp.i);
101
102     b += len;
103 #ifdef ODR_DEBUG
104     fprintf(stderr, "[val=%d]", *val);
105 #endif
106     return b - buf;
107 }