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