1use super::option::*;
19use super::*;
20
21pub fn calc_option_size(prev_key: OptionNumber, key: OptionNumber, mut value_len: usize) -> usize {
23 if value_len >= 269 {
24 value_len += 2;
25 } else if value_len >= 13 {
26 value_len += 1;
27 }
28
29 let option_delta = (key - prev_key) as u16;
30
31 if option_delta >= 269 {
32 value_len += 3;
33 } else if option_delta >= 13 {
34 value_len += 2;
35 } else {
36 value_len += 1;
37 }
38
39 return value_len;
40}
41
42pub fn decode_option<'a>(
48 iter: &mut core::slice::Iter<'a, u8>,
49 last_option: OptionNumber,
50) -> Result<Option<(OptionNumber, &'a [u8])>, Error> {
51 macro_rules! try_next {
53 ($iter:expr, $none:expr) => {
54 match ($iter).next() {
55 Some(x) => *x,
56 None => return $none,
57 }
58 };
59 }
60
61 let header: u8 = try_next!(iter, Ok(None));
62
63 if header == 0xFF {
64 return Ok(None);
66 }
67
68 let key_delta: u16 = match header >> 4 {
69 13 => 13u16 + try_next!(iter, Err(Error::ParseFailure)) as u16,
70 14 => {
71 let msb = try_next!(iter, Err(Error::ParseFailure)) as u16;
72 (269u16 + try_next!(iter, Err(Error::ParseFailure)) as u16 + (msb << 8)) as u16
73 }
74 15 => return Err(Error::ParseFailure),
75 key @ _ => key as u16,
76 };
77
78 let len = match header & 0xF {
79 13 => (13 + try_next!(iter, Err(Error::ParseFailure))) as usize,
80 14 => {
81 let msb = try_next!(iter, Err(Error::ParseFailure)) as u16;
82 (269u16 + try_next!(iter, Err(Error::ParseFailure)) as u16 + (msb << 8)) as usize
83 }
84 15 => return Err(Error::ParseFailure),
85 len @ _ => len as usize,
86 };
87
88 if last_option > core::u16::MAX - key_delta {
89 return Err(Error::ParseFailure);
91 }
92
93 if len == 0 {
94 return Ok(Some((last_option + key_delta, &[])));
95 }
96
97 let value: &'a [u8] = &iter.as_slice()[..len];
98
99 iter.nth(len - 1);
100
101 Ok(Some((last_option + key_delta, value)))
102}
103
104pub fn encode_option_without_value(
108 buffer: &mut [u8],
109 prev_key: OptionNumber,
110 key: OptionNumber,
111 value_len: usize,
112) -> Result<usize, Error> {
113 if prev_key > key {
114 return Err(Error::InvalidArgument);
115 }
116
117 let calc_len = calc_option_size(prev_key, key, value_len);
118 if calc_len > buffer.len() {
119 eprintln!("calc_len:{}, blen:{}", calc_len, buffer.len());
120 return Err(Error::OutOfSpace);
121 }
122
123 if value_len > MAX_OPTION_VALUE_SIZE {
124 eprintln!("value_len:{}, max:{}", value_len, MAX_OPTION_VALUE_SIZE);
125 return Err(Error::InvalidArgument);
126 }
127
128 let mut value_offset = 1;
129 let mut option_delta = key - prev_key;
130
131 let buffer_ptr = buffer.as_mut_ptr();
132
133 unsafe {
134 if option_delta >= 269 {
138 option_delta -= 269;
139 *buffer_ptr.offset(0) = 14 << 4;
140 *buffer_ptr.offset(1) = (option_delta >> 8) as u8;
141 *buffer_ptr.offset(2) = option_delta as u8;
142 value_offset += 2;
143 } else if option_delta >= 13 {
144 *buffer_ptr.offset(0) = 13 << 4;
145 *buffer_ptr.offset(1) = (option_delta - 13) as u8;
146 value_offset += 1;
147 } else {
148 *buffer_ptr.offset(0) = (option_delta << 4) as u8;
149 }
150
151 if value_len >= 269 {
152 *buffer_ptr.offset(0) |= 14;
153 *buffer_ptr.offset(value_offset) = ((value_len - 269) >> 8) as u8;
154 *buffer_ptr.offset(value_offset + 1) = (value_len - 269) as u8;
155 value_offset += 2;
156 } else if value_len >= 13 {
157 *buffer_ptr.offset(0) |= 13;
158 *buffer_ptr.offset(value_offset) = (value_len - 13) as u8;
159 value_offset += 1;
160 } else {
161 *buffer_ptr.offset(0) |= (value_len & 15) as u8;
162 }
163 }
164
165 return Ok(value_offset as usize + value_len);
166}
167
168pub fn encode_option(
170 buffer: &mut [u8],
171 prev_key: OptionNumber,
172 key: OptionNumber,
173 value: &[u8],
174) -> Result<usize, Error> {
175 let option_len = encode_option_without_value(buffer, prev_key, key, value.len())?;
176
177 buffer[option_len - value.len()..option_len].copy_from_slice(value);
179
180 return Ok(option_len);
181}
182
183fn insert_split_helper(
193 buffer: &[u8],
194 key: OptionNumber,
195) -> (usize, OptionNumber, OptionNumber, usize, usize) {
196 let mut prev_option_key = OptionNumber(0);
199
200 let mut split_index;
202
203 let mut iter = OptionIterator::new(buffer);
204
205 loop {
206 split_index = iter.as_slice().as_ptr() as usize - buffer.as_ptr() as usize;
207
208 let (next_key, next_value) = iter
209 .next()
210 .expect(&format!(
211 "Unexpected end of options (prev: {}, iter: {:?})",
212 prev_option_key, iter
213 ))
214 .expect("Wrote corrupt options");
215
216 if next_key > key {
217 let next_option_size =
218 iter.as_slice().as_ptr() as usize - buffer.as_ptr() as usize - split_index;
219 return (
220 split_index,
221 prev_option_key,
222 next_key,
223 next_value.len(),
224 next_option_size,
225 );
226 }
227
228 prev_option_key = next_key;
229 }
230}
231
232pub fn insert_option(
234 buffer: &mut [u8],
235 mut len: usize,
236 last_option: OptionNumber,
237 key: OptionNumber,
238 value: &[u8],
239) -> Result<(usize, OptionNumber), Error> {
240 if value.len() > MAX_OPTION_VALUE_SIZE {
241 return Err(Error::InvalidArgument);
242 }
243
244 if key >= last_option {
245 len += encode_option(&mut buffer[len..], last_option, key, value)?;
247 return Ok((len, key));
248 }
249
250 let (split_index, prev_option_key, next_option_key, next_option_value_len, next_option_size) =
256 insert_split_helper(&buffer[..len], key);
257
258 let key_delta_size_adj =
261 next_option_size - calc_option_size(key, next_option_key, next_option_value_len);
262
263 let new_option_size = calc_option_size(prev_option_key, key, value.len());
265
266 let adj_size = new_option_size - key_delta_size_adj;
268
269 if len + adj_size > buffer.len() {
271 println!(
272 "len:{} + adj_size:{} > blen:{}",
273 len,
274 adj_size,
275 buffer.len()
276 );
277 return Err(Error::OutOfSpace);
278 }
279
280 let src = split_index..len;
281 let dest = split_index + adj_size;
282
283 buffer.copy_within(src, dest);
285 len += adj_size;
286
287 encode_option(
291 &mut buffer[split_index..split_index + new_option_size],
292 prev_option_key,
293 key,
294 value,
295 )
296 .expect("Internal inconsistency inserting option");
297
298 if key != prev_option_key {
299 encode_option_without_value(
305 &mut buffer[split_index + new_option_size..],
306 key,
307 next_option_key,
308 next_option_value_len,
309 )
310 .expect("Internal inconsistency inserting option");
311 }
312
313 return Ok((len, last_option));
314}