|
1 /* |
|
2 * Copyright 2005-2006 Intel Corporation |
|
3 * |
|
4 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 * you may not use this file except in compliance with the License. |
|
6 * You may obtain a copy of the License at |
|
7 * |
|
8 * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 * |
|
10 * Unless required by applicable law or agreed to in writing, software |
|
11 * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 * See the License for the specific language governing permissions and |
|
14 * limitations under the License. |
|
15 */ |
|
16 |
|
17 /* |
|
18 * This file is a little funky since it's compiled into both C and C++ |
|
19 * (after being #included into sdnv-c.c). |
|
20 */ |
|
21 |
|
22 #ifdef HAVE_CONFIG_H |
|
23 # include <dtn-config.h> |
|
24 #endif |
|
25 |
|
26 #ifdef __cplusplus |
|
27 #include "SDNV.h" |
|
28 #include <oasys/debug/DebugUtils.h> |
|
29 #include <oasys/debug/Log.h> |
|
30 |
|
31 #define SDNV_FN(_what) SDNV::_what |
|
32 |
|
33 namespace dtn { |
|
34 |
|
35 #else // ! __cplusplus |
|
36 |
|
37 #include <stdio.h> |
|
38 #include <stdlib.h> |
|
39 #include <oasys/compat/inttypes.h> |
|
40 |
|
41 #define SDNV_FN(_what) sdnv_##_what |
|
42 |
|
43 //---------------------------------------------------------------------- |
|
44 #define ASSERT(x) \ |
|
45 do { \ |
|
46 if (! (x)) { \ |
|
47 fprintf(stderr, "ASSERTION FAILED (" #x ") at %s:%d\n", \ |
|
48 __FILE__, __LINE__); \ |
|
49 exit(1); \ |
|
50 } \ |
|
51 } while (0) |
|
52 |
|
53 //---------------------------------------------------------------------- |
|
54 #define log_err_p(p, args...) fprintf(stderr, "error: (" p ") " args); |
|
55 |
|
56 #define MAX_LENGTH 10 |
|
57 |
|
58 #endif // __cplusplus |
|
59 |
|
60 //---------------------------------------------------------------------- |
|
61 int |
|
62 SDNV_FN(encode)(u_int64_t val, u_char* bp, size_t len) |
|
63 { |
|
64 u_char* start = bp; |
|
65 |
|
66 /* |
|
67 * Figure out how many bytes we need for the encoding. |
|
68 */ |
|
69 size_t val_len = 0; |
|
70 u_int64_t tmp = val; |
|
71 |
|
72 do { |
|
73 tmp = tmp >> 7; |
|
74 val_len++; |
|
75 } while (tmp != 0); |
|
76 |
|
77 ASSERT(val_len > 0); |
|
78 ASSERT(val_len <= MAX_LENGTH); |
|
79 |
|
80 /* |
|
81 * Make sure we have enough buffer space. |
|
82 */ |
|
83 if (len < val_len) { |
|
84 return -1; |
|
85 } |
|
86 |
|
87 /* |
|
88 * Now advance bp to the last byte and fill it in backwards with |
|
89 * the value bytes. |
|
90 */ |
|
91 bp += val_len; |
|
92 u_char high_bit = 0; // for the last octet |
|
93 do { |
|
94 --bp; |
|
95 *bp = (u_char)(high_bit | (val & 0x7f)); |
|
96 high_bit = (1 << 7); // for all but the last octet |
|
97 val = val >> 7; |
|
98 } while (val != 0); |
|
99 |
|
100 ASSERT(bp == start); |
|
101 |
|
102 return val_len; |
|
103 } |
|
104 |
|
105 //---------------------------------------------------------------------- |
|
106 size_t |
|
107 SDNV_FN(encoding_len)(u_int64_t val) |
|
108 { |
|
109 u_char buf[16]; |
|
110 int ret = SDNV_FN(encode)(val, buf, sizeof(buf)); |
|
111 ASSERT(ret != -1 && ret != 0); |
|
112 return ret; |
|
113 } |
|
114 |
|
115 //---------------------------------------------------------------------- |
|
116 int |
|
117 SDNV_FN(decode)(const u_char* bp, size_t len, u_int64_t* val) |
|
118 { |
|
119 const u_char* start = bp; |
|
120 |
|
121 if (!val) { |
|
122 return -1; |
|
123 } |
|
124 |
|
125 /* |
|
126 * Zero out the existing value, then shift in the bytes of the |
|
127 * encoding one by one until we hit a byte that has a zero |
|
128 * high-order bit. |
|
129 */ |
|
130 size_t val_len = 0; |
|
131 *val = 0; |
|
132 do { |
|
133 if (len == 0) |
|
134 return -1; // buffer too short |
|
135 |
|
136 *val = (*val << 7) | (*bp & 0x7f); |
|
137 ++val_len; |
|
138 |
|
139 if ((*bp & (1 << 7)) == 0) |
|
140 break; // all done; |
|
141 |
|
142 ++bp; |
|
143 --len; |
|
144 } while (1); |
|
145 |
|
146 /* |
|
147 * Since the spec allows for infinite length values but this |
|
148 * implementation only handles up to 64 bits, check for overflow. |
|
149 * Note that the only supportable 10 byte SDNV must store exactly |
|
150 * one bit in the first byte of the encoding (i.e. the 64'th bit |
|
151 * of the original value). |
|
152 * This is OK because a spec update says that behavior |
|
153 * is undefined for values > 64 bits. |
|
154 */ |
|
155 if ((val_len > MAX_LENGTH) || |
|
156 ((val_len == MAX_LENGTH) && (*start != 0x81))) |
|
157 { |
|
158 log_err_p("/dtn/bundle/sdnv", "overflow value in sdnv!!!"); |
|
159 return -1; |
|
160 } |
|
161 |
|
162 // XXX/demmer shouldn't use -1 as indication of both too short of |
|
163 // a buffer and of error due to overflow or malformed SDNV since |
|
164 // callers just assume that they need more data to decode and |
|
165 // don't really check for errors |
|
166 |
|
167 return val_len; |
|
168 } |
|
169 |
|
170 //---------------------------------------------------------------------- |
|
171 size_t |
|
172 SDNV_FN(len)(const u_char* bp) |
|
173 { |
|
174 size_t val_len = 1; |
|
175 |
|
176 for ( ; *bp++ & 0x80; ++val_len ) |
|
177 ; |
|
178 return val_len; |
|
179 } |
|
180 |
|
181 #ifdef __cplusplus |
|
182 } // namespace dtn |
|
183 #endif |
|
184 |