1use core::cmp::min;
2
3#[repr(C)]
4#[derive(Debug, Clone, Copy, PartialEq)]
5pub enum BroCatliResult {
6 Success = 0,
7 NeedsMoreInput = 1,
8 NeedsMoreOutput = 2,
9 BrotliFileNotCraftedForAppend = 124,
10 InvalidWindowSize = 125,
11 WindowSizeLargerThanPreviousFile = 126,
12 BrotliFileNotCraftedForConcatenation = 127,
13}
14
15const NUM_STREAM_HEADER_BYTES: usize = 5;
16
17#[derive(Clone, Copy)]
18struct NewStreamData {
19 bytes_so_far: [u8; NUM_STREAM_HEADER_BYTES],
20 num_bytes_read: u8,
21 num_bytes_written: Option<u8>,
22}
23impl NewStreamData {
24 pub fn new() -> NewStreamData {
25 NewStreamData {
26 bytes_so_far: [0, 0, 0, 0, 0],
27 num_bytes_read: 0,
28 num_bytes_written: None,
29 }
30 }
31 fn sufficient(&self) -> bool {
32 if self.num_bytes_read == 4 && (127 & self.bytes_so_far[0]) != 17 {
33 return true;
34 }
35 self.num_bytes_read == 5
36 }
37}
38
39fn parse_window_size(bytes_so_far: &[u8]) -> Result<(u8, usize), ()> {
40 if bytes_so_far[0] & 1 == 0 {
42 return Ok((16, 1));
43 }
44 match bytes_so_far[0] & 15 {
45 0x3 => return Ok((18, 4)),
46 0x5 => return Ok((19, 4)),
47 0x7 => return Ok((20, 4)),
48 0x9 => return Ok((21, 4)),
49 0xb => return Ok((22, 4)),
50 0xd => return Ok((23, 4)),
51 0xf => return Ok((24, 4)),
52 _ => match bytes_so_far[0] & 127 {
53 0x71 => return Ok((15, 7)),
54 0x61 => return Ok((14, 7)),
55 0x51 => return Ok((13, 7)),
56 0x41 => return Ok((12, 7)),
57 0x31 => return Ok((11, 7)),
58 0x21 => return Ok((10, 7)),
59 0x1 => return Ok((17, 7)),
60 _ => {}
61 },
62 }
63 if (bytes_so_far[0] & 0x80) != 0 {
64 return Err(());
65 }
66 let ret = bytes_so_far[1] & 0x3f;
67 if !(10..=30).contains(&ret) {
68 return Err(());
69 }
70 Ok((ret, 14))
71}
72
73fn detect_varlen_offset(bytes_so_far: &[u8]) -> Result<(usize), ()> {
74 let (_, mut offset) = match parse_window_size(bytes_so_far) {
76 Ok(x) => x,
77 Err(_) => return Err(()),
78 };
79 let mut bytes = 0u64;
80 for (index, item) in bytes_so_far.iter().enumerate() {
81 bytes |= u64::from(*item) << (index * 8);
82 }
83 bytes >>= offset;
84 offset += 1;
85 if (bytes & 1) != 0 {
86 bytes >>= 1;
88 offset += 1;
89 if (bytes & 1) != 0 {
90 return Ok(offset);
92 }
93 }
94 bytes >>= 1;
95 let mut mnibbles = bytes & 3;
96 bytes >>= 2;
97 offset += 2;
98 if mnibbles == 3 {
99 if (bytes & 1) != 0 {
101 return Err(()); }
103 bytes >>= 1;
104 offset += 1;
105 let mskipbytes = bytes & ((1 << 2) - 1);
106 offset += 2;
107 offset += (mskipbytes as usize) * 8; return Ok(offset);
109 }
110 mnibbles += 4;
111 offset += (mnibbles as usize) * 4;
112 bytes >>= mnibbles * 4;
113 offset += 1;
114 if (bytes & 1) == 0 {
115 Err(()) } else {
118 Ok(offset)
120 }
121}
122
123#[derive(Default)]
125pub struct BroCatli {
126 last_bytes: [u8; 2],
127 last_bytes_len: u8,
128 last_byte_sanitized: bool,
129 any_bytes_emitted: bool,
130 last_byte_bit_offset: u8,
131 window_size: u8,
133 new_stream_pending: Option<NewStreamData>,
134}
135
136impl BroCatli {
137 pub fn new() -> Self {
138 Self::default()
139 }
140
141 pub fn deserialize_from_buffer(buffer: &[u8]) -> Result<BroCatli, ()> {
142 if 16 + NUM_STREAM_HEADER_BYTES > buffer.len() {
143 return Err(());
144 }
145 let mut possible_new_stream_pending = NewStreamData {
146 num_bytes_read: buffer[12],
147 num_bytes_written: if (buffer[9] & (1 << 7)) != 0 {
148 Some(buffer[13])
149 } else {
150 None
151 },
152 bytes_so_far: [0; NUM_STREAM_HEADER_BYTES],
153 };
154 let xlen = possible_new_stream_pending.bytes_so_far.len();
155 possible_new_stream_pending
156 .bytes_so_far
157 .clone_from_slice(&buffer[16..16 + xlen]);
158 let new_stream_pending: Option<NewStreamData> = if (buffer[9] & (1 << 6)) != 0 {
159 Some(possible_new_stream_pending)
160 } else {
161 None
162 };
163 let mut ret = BroCatli {
164 last_bytes: [0, 0],
165 last_bytes_len: buffer[8],
166 last_byte_sanitized: (buffer[9] & 0x1) != 0,
167 last_byte_bit_offset: buffer[10],
168 any_bytes_emitted: (buffer[9] & (1 << 5)) != 0,
169 window_size: buffer[11],
170 new_stream_pending,
171 };
172 if ret.last_bytes.len() > 8 {
173 return Err(());
174 }
175 let xlen = ret.last_bytes.len();
176 ret.last_bytes.clone_from_slice(&buffer[..xlen]);
177 Ok(ret)
178 }
179 #[inline(always)]
180 pub fn serialize_to_buffer(&self, buffer: &mut [u8]) -> Result<(), ()> {
181 if 16 + NUM_STREAM_HEADER_BYTES > buffer.len() {
182 return Err(());
183 }
184 buffer[..self.last_bytes.len()].clone_from_slice(&self.last_bytes[..]);
185 buffer[8] = self.last_bytes_len;
186 buffer[9] = (self.last_byte_sanitized as u8)
187 | ((self.new_stream_pending.is_some() as u8) << 6)
188 | ((self.any_bytes_emitted as u8) << 5);
189 buffer[10] = self.last_byte_bit_offset;
190 buffer[11] = self.window_size;
191 if let Some(new_stream_pending) = self.new_stream_pending {
192 if new_stream_pending.num_bytes_written.is_some() {
193 buffer[9] |= (1 << 7);
194 }
195 buffer[12] = new_stream_pending.num_bytes_read;
196 buffer[13] = new_stream_pending.num_bytes_written.unwrap_or(0);
197 buffer[16..16 + new_stream_pending.bytes_so_far.len()]
199 .clone_from_slice(&new_stream_pending.bytes_so_far[..]);
200 }
201 Ok(())
202 }
203 pub fn new_with_window_size(log_window_size: u8) -> BroCatli {
204 let last_bytes_len;
211 let last_bytes;
212
213 if log_window_size > 24 {
214 last_bytes = [17u8, log_window_size | 64 | 128];
215 last_bytes_len = 2;
216 } else if log_window_size == 16 {
217 last_bytes = [1 | 2 | 4, 0];
218 last_bytes_len = 1;
219 } else if log_window_size > 17 {
220 last_bytes = [(3 + (log_window_size - 18) * 2) | (16 | 32), 0];
221 last_bytes_len = 1;
222 } else {
223 match log_window_size {
224 15 => last_bytes = [0x71 | 0x80, 1],
225 14 => last_bytes = [0x61 | 0x80, 1],
226 13 => last_bytes = [0x51 | 0x80, 1],
227 12 => last_bytes = [0x41 | 0x80, 1],
228 11 => last_bytes = [0x31 | 0x80, 1],
229 10 => last_bytes = [0x21 | 0x80, 1],
230 _ => {
231 assert_eq!(log_window_size, 17);
232 last_bytes = [0x1 | 0x80, 1];
233 } }
235 last_bytes_len = 2;
236 }
237 BroCatli {
238 last_bytes,
239 last_bytes_len,
240 last_byte_bit_offset: 0,
241 last_byte_sanitized: false,
242 any_bytes_emitted: false,
243 new_stream_pending: None,
244 window_size: log_window_size,
245 }
246 }
247
248 pub fn new_brotli_file(&mut self) {
249 self.new_stream_pending = Some(NewStreamData::new());
250 }
251 fn flush_previous_stream(
252 &mut self,
253 out_bytes: &mut [u8],
254 out_offset: &mut usize,
255 ) -> BroCatliResult {
256 if !self.last_byte_sanitized {
257 if self.last_bytes_len == 0 {
259 self.last_byte_sanitized = true;
261 return BroCatliResult::Success;
262 }
263 let mut last_bytes = self.last_bytes[0] as u16 + ((self.last_bytes[1] as u16) << 8);
265 let max = self.last_bytes_len * 8;
266 let mut index = max - 1;
267 for i in 0..max {
268 index = max - 1 - i;
269 if ((1 << index) & last_bytes) != 0 {
270 break; }
272 }
273 if index == 0 {
274 return BroCatliResult::BrotliFileNotCraftedForAppend;
276 }
277 if (last_bytes >> (index - 1)) != 3 {
278 return BroCatliResult::BrotliFileNotCraftedForAppend;
280 }
281 index -= 1; last_bytes &= (1 << index) - 1; self.last_bytes[0] = last_bytes as u8; self.last_bytes[1] = (last_bytes >> 8) as u8;
285 if index >= 8 {
286 if out_bytes.len() > *out_offset {
288 out_bytes[*out_offset] = self.last_bytes[0];
289 self.last_bytes[0] = self.last_bytes[1];
290 *out_offset += 1;
291 self.any_bytes_emitted = true;
292 index -= 8;
293 self.last_bytes_len -= 1;
294 } else {
295 return BroCatliResult::NeedsMoreOutput;
296 }
297 }
298 self.last_byte_bit_offset = index;
299 assert!(index < 8);
300 self.last_byte_sanitized = true;
301 }
302 BroCatliResult::Success
303 }
304
305 fn shift_and_check_new_stream_header(
306 &mut self,
307 mut new_stream_pending: NewStreamData,
308 out_bytes: &mut [u8],
309 out_offset: &mut usize,
310 ) -> BroCatliResult {
311 if new_stream_pending.num_bytes_written.is_none() {
312 let (window_size, window_offset) = if let Ok(results) = parse_window_size(
313 &new_stream_pending.bytes_so_far[..usize::from(new_stream_pending.num_bytes_read)],
314 ) {
315 results
316 } else {
317 return BroCatliResult::InvalidWindowSize;
318 };
319 if self.window_size == 0 {
320 self.window_size = window_size;
322 assert_eq!(self.last_byte_bit_offset, 0); out_bytes[*out_offset] = new_stream_pending.bytes_so_far[0];
324 new_stream_pending.num_bytes_written = Some(1);
325 self.any_bytes_emitted = true;
326 *out_offset += 1;
327 } else {
328 if window_size > self.window_size {
329 return BroCatliResult::WindowSizeLargerThanPreviousFile;
330 }
331 let mut realigned_header: [u8; NUM_STREAM_HEADER_BYTES + 1] =
332 [self.last_bytes[0], 0, 0, 0, 0, 0];
333 let varlen_offset = if let Ok(voffset) = detect_varlen_offset(
334 &new_stream_pending.bytes_so_far
335 [..usize::from(new_stream_pending.num_bytes_read)],
336 ) {
337 voffset
338 } else {
339 return BroCatliResult::BrotliFileNotCraftedForConcatenation;
340 };
341 let mut bytes_so_far = 0u64;
342 for index in 0..usize::from(new_stream_pending.num_bytes_read) {
343 bytes_so_far |=
344 u64::from(new_stream_pending.bytes_so_far[index]) << (index * 8);
345 }
346 bytes_so_far >>= window_offset; bytes_so_far &= (1u64 << (varlen_offset - window_offset)) - 1;
348 let var_len_bytes = (((varlen_offset - window_offset) + 7) / 8);
349 for byte_index in 0..var_len_bytes {
350 let cur_byte = (bytes_so_far >> (byte_index * 8));
351 realigned_header[byte_index] |=
352 ((cur_byte & ((1 << (8 - self.last_byte_bit_offset)) - 1))
353 << self.last_byte_bit_offset) as u8;
354 realigned_header[byte_index + 1] =
355 (cur_byte >> (8 - self.last_byte_bit_offset)) as u8;
356 }
357 let whole_byte_destination =
358 ((usize::from(self.last_byte_bit_offset) + varlen_offset - window_offset) + 7)
359 / 8;
360 let whole_byte_source = (varlen_offset + 7) / 8;
361 let num_whole_bytes_to_copy =
362 usize::from(new_stream_pending.num_bytes_read) - whole_byte_source;
363 for aligned_index in 0..num_whole_bytes_to_copy {
364 realigned_header[whole_byte_destination + aligned_index] =
365 new_stream_pending.bytes_so_far[whole_byte_source + aligned_index];
366 }
367 out_bytes[*out_offset] = realigned_header[0];
368 self.any_bytes_emitted = true;
369 *out_offset += 1;
370 new_stream_pending.num_bytes_read =
372 (whole_byte_destination + num_whole_bytes_to_copy) as u8 - 1;
373 new_stream_pending.num_bytes_written = Some(0);
374 new_stream_pending
375 .bytes_so_far
376 .clone_from_slice(&realigned_header[1..]);
377 }
378 } else {
379 assert_ne!(self.window_size, 0);
380 }
381 let to_copy = min(
382 out_bytes.len() - *out_offset,
383 usize::from(
384 new_stream_pending.num_bytes_read - new_stream_pending.num_bytes_written.unwrap(),
385 ),
386 );
387 out_bytes
388 .split_at_mut(*out_offset)
389 .1
390 .split_at_mut(to_copy)
391 .0
392 .clone_from_slice(
393 new_stream_pending
394 .bytes_so_far
395 .split_at(usize::from(new_stream_pending.num_bytes_written.unwrap()))
396 .1
397 .split_at(to_copy)
398 .0,
399 );
400 *out_offset += to_copy;
401 if to_copy != 0 {
402 self.any_bytes_emitted = true;
403 }
404 new_stream_pending.num_bytes_written =
405 Some((new_stream_pending.num_bytes_written.unwrap() + to_copy as u8));
406 if new_stream_pending.num_bytes_written.unwrap() != new_stream_pending.num_bytes_read {
407 self.new_stream_pending = Some(new_stream_pending);
408 return BroCatliResult::NeedsMoreOutput;
409 }
410 self.new_stream_pending = None;
411 self.last_byte_sanitized = false;
412 self.last_byte_bit_offset = 0;
413 self.last_bytes_len = 0;
414 self.last_bytes = [0, 0];
415 *out_offset -= 1;
417 self.last_bytes[0] = out_bytes[*out_offset];
418 self.last_bytes_len = 1;
419 BroCatliResult::Success
420 }
421 pub fn stream(
422 &mut self,
423 in_bytes: &[u8],
424 in_offset: &mut usize,
425 out_bytes: &mut [u8],
426 out_offset: &mut usize,
427 ) -> BroCatliResult {
428 if let Some(mut new_stream_pending) = self.new_stream_pending {
429 let flush_result = self.flush_previous_stream(out_bytes, out_offset);
430 if let BroCatliResult::Success = flush_result {
431 if usize::from(new_stream_pending.num_bytes_read)
432 < new_stream_pending.bytes_so_far.len()
433 {
434 {
435 let dst = &mut new_stream_pending.bytes_so_far
436 [usize::from(new_stream_pending.num_bytes_read)..];
437 let to_copy = min(dst.len(), in_bytes.len() - *in_offset);
438 dst[..to_copy]
439 .clone_from_slice(in_bytes.split_at(*in_offset).1.split_at(to_copy).0);
440 *in_offset += to_copy;
441 new_stream_pending.num_bytes_read += to_copy as u8;
442 }
443 self.new_stream_pending = Some(new_stream_pending); }
445 if !new_stream_pending.sufficient() {
446 return BroCatliResult::NeedsMoreInput;
447 }
448 if out_bytes.len() == *out_offset {
449 return BroCatliResult::NeedsMoreOutput;
450 }
451 let shift_result = self.shift_and_check_new_stream_header(
452 new_stream_pending,
453 out_bytes,
454 out_offset,
455 );
456 if let BroCatliResult::Success = shift_result {
457 } else {
458 return shift_result;
459 }
460 } else {
461 return flush_result;
462 }
463 if *out_offset == out_bytes.len() {
464 return BroCatliResult::NeedsMoreOutput; }
466 }
467 assert!(self.new_stream_pending.is_none()); if self.last_bytes_len != 2 {
469 if out_bytes.len() == *out_offset {
470 return BroCatliResult::NeedsMoreOutput;
471 }
472 if in_bytes.len() == *in_offset {
473 return BroCatliResult::NeedsMoreInput;
474 }
475 self.last_bytes[usize::from(self.last_bytes_len)] = in_bytes[*in_offset];
476 *in_offset += 1;
477 self.last_bytes_len += 1;
478 if self.last_bytes_len != 2 {
479 if out_bytes.len() == *out_offset {
480 return BroCatliResult::NeedsMoreOutput;
481 }
482 if in_bytes.len() == *in_offset {
483 return BroCatliResult::NeedsMoreInput;
484 }
485 self.last_bytes[usize::from(self.last_bytes_len)] = in_bytes[*in_offset];
486 self.last_bytes_len += 1;
487 *in_offset += 1;
488 }
489 }
490 if out_bytes.len() == *out_offset {
491 return BroCatliResult::NeedsMoreOutput;
492 }
493 if in_bytes.len() == *in_offset {
494 return BroCatliResult::NeedsMoreInput;
495 }
496 let mut to_copy = min(out_bytes.len() - *out_offset, in_bytes.len() - *in_offset);
497 assert_ne!(to_copy, 0);
498 if to_copy == 1 {
499 out_bytes[*out_offset] = self.last_bytes[0];
500 self.last_bytes[0] = self.last_bytes[1];
501 self.last_bytes[1] = in_bytes[*in_offset];
502 *in_offset += 1;
503 *out_offset += 1;
504 if *out_offset == out_bytes.len() {
505 return BroCatliResult::NeedsMoreOutput;
506 }
507 return BroCatliResult::NeedsMoreInput;
508 }
509 out_bytes
510 .split_at_mut(*out_offset)
511 .1
512 .split_at_mut(2)
513 .0
514 .clone_from_slice(&self.last_bytes[..]);
515 *out_offset += 2;
516 let (new_in_offset, last_two) = in_bytes
517 .split_at(*in_offset)
518 .1
519 .split_at(to_copy)
520 .0
521 .split_at(to_copy - 2);
522 self.last_bytes.clone_from_slice(last_two);
523 *in_offset += 2; to_copy -= 2;
525 out_bytes
526 .split_at_mut(*out_offset)
527 .1
528 .split_at_mut(to_copy)
529 .0
530 .clone_from_slice(new_in_offset);
531 *out_offset += to_copy;
532 *in_offset += to_copy;
533 if *out_offset == out_bytes.len() {
534 return BroCatliResult::NeedsMoreOutput;
535 }
536 BroCatliResult::NeedsMoreInput
537 }
538 fn append_eof_metablock_to_last_bytes(&mut self) {
539 assert!(self.last_byte_sanitized);
540 let mut last_bytes = self.last_bytes[0] as u16 | ((self.last_bytes[1] as u16) << 8);
541 let bit_end = (self.last_bytes_len - 1) * 8 + self.last_byte_bit_offset;
542 last_bytes |= 3 << bit_end;
543 self.last_bytes[0] = last_bytes as u8;
544 self.last_bytes[1] = (last_bytes >> 8) as u8;
545 self.last_byte_sanitized = false;
546 self.last_byte_bit_offset += 2;
547 if self.last_byte_bit_offset >= 8 {
548 self.last_byte_bit_offset -= 8;
549 self.last_bytes_len += 1;
550 }
551 }
552 pub fn finish(&mut self, out_bytes: &mut [u8], out_offset: &mut usize) -> BroCatliResult {
553 if self.last_byte_sanitized && self.last_bytes_len != 0 {
554 self.append_eof_metablock_to_last_bytes();
555 }
556 while self.last_bytes_len != 0 {
557 if *out_offset == out_bytes.len() {
558 return BroCatliResult::NeedsMoreOutput;
559 }
560 out_bytes[*out_offset] = self.last_bytes[0];
561 *out_offset += 1;
562 self.last_bytes_len -= 1;
563 self.last_bytes[0] = self.last_bytes[1];
564 self.any_bytes_emitted = true;
565 }
566 if !self.any_bytes_emitted {
567 if out_bytes.len() == *out_offset {
568 return BroCatliResult::NeedsMoreOutput;
569 }
570 self.any_bytes_emitted = true;
571 out_bytes[*out_offset] = b';';
572 *out_offset += 1;
573 }
574 BroCatliResult::Success
575 }
576}
577
578#[cfg(test)]
579mod test {
580 use super::BroCatli;
581
582 #[test]
583 fn test_deserialization() {
584 let broccoli = BroCatli {
585 new_stream_pending: Some(super::NewStreamData {
586 bytes_so_far: [0x33; super::NUM_STREAM_HEADER_BYTES],
587 num_bytes_read: 16,
588 num_bytes_written: Some(3),
589 }),
590 last_bytes: [0x45, 0x46],
591 last_bytes_len: 1,
592 last_byte_sanitized: true,
593 any_bytes_emitted: false,
594 last_byte_bit_offset: 7,
595 window_size: 22,
596 };
597 let mut buffer = [0u8; 248];
598 broccoli.serialize_to_buffer(&mut buffer[..]).unwrap();
599 let bc = BroCatli::deserialize_from_buffer(&buffer[..]).unwrap();
600 assert_eq!(broccoli.last_bytes, bc.last_bytes);
601 assert_eq!(broccoli.last_bytes_len, bc.last_bytes_len);
602 assert_eq!(broccoli.last_byte_sanitized, bc.last_byte_sanitized);
603 assert_eq!(broccoli.last_byte_bit_offset, bc.last_byte_bit_offset);
604 assert_eq!(broccoli.window_size, bc.window_size);
605 assert_eq!(
606 broccoli.new_stream_pending.unwrap().bytes_so_far,
607 bc.new_stream_pending.unwrap().bytes_so_far
608 );
609 assert_eq!(
610 broccoli.new_stream_pending.unwrap().num_bytes_read,
611 bc.new_stream_pending.unwrap().num_bytes_read
612 );
613 assert_eq!(
614 broccoli.new_stream_pending.unwrap().num_bytes_written,
615 bc.new_stream_pending.unwrap().num_bytes_written
616 );
617 }
618 #[test]
619 fn test_deserialization_any_written() {
620 let broccoli = BroCatli {
621 new_stream_pending: Some(super::NewStreamData {
622 bytes_so_far: [0x33; super::NUM_STREAM_HEADER_BYTES],
623 num_bytes_read: 16,
624 num_bytes_written: Some(3),
625 }),
626 last_bytes: [0x45, 0x46],
627 last_bytes_len: 1,
628 last_byte_sanitized: true,
629 any_bytes_emitted: true,
630 last_byte_bit_offset: 7,
631 window_size: 22,
632 };
633 let mut buffer = [0u8; 248];
634 broccoli.serialize_to_buffer(&mut buffer[..]).unwrap();
635 let bc = BroCatli::deserialize_from_buffer(&buffer[..]).unwrap();
636 assert_eq!(broccoli.last_bytes, bc.last_bytes);
637 assert_eq!(broccoli.last_bytes_len, bc.last_bytes_len);
638 assert_eq!(broccoli.last_byte_sanitized, bc.last_byte_sanitized);
639 assert_eq!(broccoli.last_byte_bit_offset, bc.last_byte_bit_offset);
640 assert_eq!(broccoli.window_size, bc.window_size);
641 assert_eq!(
642 broccoli.new_stream_pending.unwrap().bytes_so_far,
643 bc.new_stream_pending.unwrap().bytes_so_far
644 );
645 assert_eq!(
646 broccoli.new_stream_pending.unwrap().num_bytes_read,
647 bc.new_stream_pending.unwrap().num_bytes_read
648 );
649 assert_eq!(
650 broccoli.new_stream_pending.unwrap().num_bytes_written,
651 bc.new_stream_pending.unwrap().num_bytes_written
652 );
653 }
654 #[test]
655 fn test_serialization() {
656 let mut buffer = [0u8; 248];
657 let mut broccoli = BroCatli::deserialize_from_buffer(&buffer).unwrap();
658 let mut buffer2 = [0u8; 248];
659 broccoli.serialize_to_buffer(&mut buffer2[..]).unwrap();
660 assert_eq!(&buffer[..], &buffer2[..]);
661 for (index, item) in buffer.iter_mut().enumerate() {
662 *item = index as u8;
663 }
664 broccoli = BroCatli::deserialize_from_buffer(&buffer).unwrap();
665 broccoli.serialize_to_buffer(&mut buffer2[..]).unwrap();
666 broccoli = BroCatli::deserialize_from_buffer(&buffer2).unwrap();
667 for (_index, item) in buffer.iter_mut().enumerate() {
668 *item = 0;
669 }
670 broccoli.serialize_to_buffer(&mut buffer[..]).unwrap();
671 assert_eq!(&buffer[..], &buffer2[..]);
672 for (index, item) in buffer.iter_mut().enumerate() {
673 *item = 0xff ^ index as u8;
674 }
675 broccoli = BroCatli::deserialize_from_buffer(&buffer).unwrap();
676 broccoli.serialize_to_buffer(&mut buffer2[..]).unwrap();
677 broccoli = BroCatli::deserialize_from_buffer(&buffer2).unwrap();
678 for (_index, item) in buffer.iter_mut().enumerate() {
679 *item = 0;
680 }
681 broccoli.serialize_to_buffer(&mut buffer[..]).unwrap();
682 assert_eq!(&buffer[..], &buffer2[..]);
683 }
684 #[test]
685 fn test_cat_empty_stream() {
686 let empty_catable = [b';'];
687 let mut bcat = super::BroCatli::default();
688 let mut in_offset = 0usize;
689 let mut out_bytes = [0u8; 32];
690 let mut out_offset = 0usize;
691 bcat.new_brotli_file();
692 let mut res = bcat.stream(
693 &empty_catable[..],
694 &mut in_offset,
695 &mut out_bytes[..],
696 &mut out_offset,
697 );
698 assert_eq!(res, super::BroCatliResult::NeedsMoreInput);
699 bcat.new_brotli_file();
700 in_offset = 0;
701 res = bcat.stream(
702 &empty_catable[..],
703 &mut in_offset,
704 &mut out_bytes[..],
705 &mut out_offset,
706 );
707 assert_eq!(res, super::BroCatliResult::NeedsMoreInput);
708 res = bcat.finish(&mut out_bytes[..], &mut out_offset);
709 assert_eq!(res, super::BroCatliResult::Success);
710 assert_ne!(out_offset, 0);
711 assert_eq!(&out_bytes[..out_offset], &[b';']);
712 }
713}