1 use core;
2 
3 #[repr(C)]
4 #[derive(Debug,Clone,Copy, PartialEq)]
5 pub 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 
15 const NUM_STREAM_HEADER_BYTES: usize = 5;
16 
17 #[derive(Clone,Copy)]
18 struct NewStreamData {
19     bytes_so_far: [u8;NUM_STREAM_HEADER_BYTES],
20     num_bytes_read: u8,
21     num_bytes_written: Option<u8>,
22 }
23 impl NewStreamData {
new() -> NewStreamData24     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     }
sufficient(&self) -> bool31     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 
parse_window_size(bytes_so_far:&[u8]) -> Result<(u8, usize), ()>39 fn parse_window_size(bytes_so_far:&[u8]) -> Result<(u8, usize), ()> {  // returns window_size and offset in stream in bits
40   if bytes_so_far[0] & 1 == 0 {
41     return Ok((16, 1));
42   }
43   match bytes_so_far[0] & 15 {
44     0x3 => return Ok((18, 4)),
45     0x5 => return Ok((19, 4)),
46     0x7 => return Ok((20, 4)),
47     0x9 => return Ok((21, 4)),
48     0xb => return Ok((22, 4)),
49     0xd => return Ok((23, 4)),
50     0xf => return Ok((24, 4)),
51     _ => match bytes_so_far[0] & 127 {
52       0x71 => return Ok((15, 7)),
53       0x61 => return Ok((14, 7)),
54       0x51 => return Ok((13, 7)),
55       0x41 => return Ok((12, 7)),
56       0x31 => return Ok((11, 7)),
57       0x21 => return Ok((10, 7)),
58       0x1 => return Ok((17, 7)),
59       _ => {},
60     }
61   }
62   if (bytes_so_far[0] & 0x80) != 0 {
63     return Err(());
64   }
65   let ret  = bytes_so_far[1] & 0x3f;
66   if ret < 10 || ret > 30 {
67     return Err(());
68   }
69   Ok((ret, 14))
70 }
71 
detect_varlen_offset(bytes_so_far:&[u8]) -> Result<(usize), ()>72 fn detect_varlen_offset(bytes_so_far:&[u8]) -> Result<(usize), ()> {  // returns offfset in bits
73   let (_, mut offset) = match parse_window_size(bytes_so_far) {
74     Ok(x) => x,
75     Err(_) => return Err(()),
76   };
77   let mut bytes = 0u64;
78   for (index, item) in bytes_so_far.iter().enumerate() {
79     bytes |= u64::from(*item) << (index * 8);
80   }
81   bytes >>= offset;
82   offset += 1;
83   if (bytes & 1) != 0 { // ISLAST
84     bytes >>= 1;
85     offset += 1;
86     if (bytes & 1) != 0 { // ISLASTEMPTY
87       return Ok(offset);
88     }
89   }
90   bytes >>= 1;
91   let mut mnibbles = bytes & 3;
92   bytes >>= 2;
93   offset += 2;
94   if mnibbles == 3 { // metadata block
95     if (bytes & 1) != 0 {
96       return Err(()); // reserved, must be zero
97     }
98     bytes >>= 1;
99     offset += 1;
100     let mskipbytes = bytes & ((1 << 2) - 1);
101     offset += 2;
102     offset += usize::from(mskipbytes as usize) * 8; // next item is byte aligned
103     return Ok(offset);
104   }
105   mnibbles += 4;
106   offset += usize::from(mnibbles as usize) * 4;
107   bytes >>= mnibbles * 4;
108   offset += 1;
109   if (bytes & 1) == 0 { // not UNCOMPRESSED
110     Err(()) // not valid bitstream for concatenation
111   } else { // UNCOMPRESSED: now things are aligend
112     Ok(offset)
113   }
114 }
115 
116 // eat your vegetables
117 pub struct BroCatli {
118   last_bytes: [u8; 2],
119   last_bytes_len: u8,
120   last_byte_sanitized: bool,
121   any_bytes_emitted: bool,
122   last_byte_bit_offset: u8,
123   // need to make sure that window sizes stay similar or get smaller
124   window_size: u8,
125   new_stream_pending: Option<NewStreamData>,
126 }
127 impl Default for BroCatli {
default() -> BroCatli128     fn default() -> BroCatli {
129         BroCatli::new()
130     }
131 }
132 impl BroCatli {
new() -> BroCatli133   pub fn new() -> BroCatli {
134     BroCatli {
135       last_bytes: [0,0],
136       last_bytes_len: 0,
137       last_byte_bit_offset: 0,
138       last_byte_sanitized: false,
139       any_bytes_emitted: false,
140       new_stream_pending: None,
141       window_size:0,
142     }
143   }
deserialize_from_buffer(buffer: &[u8]) -> Result<BroCatli, ()>144   pub fn deserialize_from_buffer(buffer: &[u8]) -> Result<BroCatli, ()> {
145     if 16+NUM_STREAM_HEADER_BYTES > buffer.len() {
146         return Err(());
147     }
148     let mut possible_new_stream_pending = NewStreamData{
149         num_bytes_read: buffer[12],
150         num_bytes_written: if (buffer[9] & (1<<7)) != 0 {Some(buffer[13])} else {None},
151         bytes_so_far: [0;NUM_STREAM_HEADER_BYTES],
152     };
153     let xlen = possible_new_stream_pending.bytes_so_far.len();
154     possible_new_stream_pending.bytes_so_far.clone_from_slice(
155         &buffer[16..16+xlen]);
156     let new_stream_pending: Option<NewStreamData> = if (buffer[9] & (1 << 6)) != 0 {
157         Some(possible_new_stream_pending)
158     } else {
159         None
160     };
161     let mut ret = BroCatli {
162         last_bytes: [0,0],
163         last_bytes_len: buffer[8],
164         last_byte_sanitized: (buffer[9] & 0x1) != 0,
165         last_byte_bit_offset: buffer[10],
166         any_bytes_emitted: (buffer[9] & (1 << 5)) != 0,
167         window_size: buffer[11],
168         new_stream_pending:new_stream_pending,
169     };
170     if ret.last_bytes.len() > 8 {
171         return Err(());
172     }
173     let xlen = ret.last_bytes.len();
174     ret.last_bytes.clone_from_slice(&buffer[..xlen]);
175     Ok(ret)
176   }
177   #[inline(always)]
serialize_to_buffer(&self, buffer: &mut [u8]) -> Result<(), ()>178   pub fn serialize_to_buffer(&self, buffer: &mut [u8]) -> Result<(), ()> {
179     if 16+NUM_STREAM_HEADER_BYTES > buffer.len() {
180         return Err(());
181     }
182     buffer[..self.last_bytes.len()].clone_from_slice(
183         &self.last_bytes[..]);
184     buffer[8] = self.last_bytes_len;
185     buffer[9] = (self.last_byte_sanitized as u8) | ((self.new_stream_pending.is_some() as u8) << 6) | ((self.any_bytes_emitted as u8) << 5);
186       buffer[10] = self.last_byte_bit_offset;
187       buffer[11] = self.window_size;
188       if let Some(new_stream_pending) = self.new_stream_pending {
189           if new_stream_pending.num_bytes_written.is_some() {
190               buffer[9] |= (1<<7);
191           }
192           buffer[12] = new_stream_pending.num_bytes_read;
193           buffer[13] = new_stream_pending.num_bytes_written.unwrap_or(0);
194           // 14, 15 reserved
195           buffer[16..16+new_stream_pending.bytes_so_far.len()].clone_from_slice(
196               &new_stream_pending.bytes_so_far[..]);
197       }
198       Ok(())
199   }
new_with_window_size(log_window_size: u8) -> BroCatli200   pub fn new_with_window_size(log_window_size: u8) -> BroCatli {
201     // in this case setup the last_bytes of the stream to perfectly mimic what would
202     // appear in an empty stream with the selected window size...
203     // this means the window size followed by 2 sequential 1 bits (LAST_METABLOCK, EMPTY)
204     // the new_stream code should naturally find the sequential 1 bits and mask them
205     // out and then prepend the window size... then the following window sizes should
206     // be checked to be shorter
207     let last_bytes_len;
208     let last_bytes;
209 
210     if log_window_size > 24 {
211         last_bytes = [17u8, log_window_size | 64 | 128];
212         last_bytes_len = 2;
213     } else if log_window_size == 16 {
214         last_bytes = [1 | 2 | 4, 0];
215         last_bytes_len = 1;
216     } else if log_window_size > 17 {
217         last_bytes = [(3 + (log_window_size - 18) * 2) | (16 | 32), 0];
218         last_bytes_len = 1;
219     } else {
220         match log_window_size {
221             15 => last_bytes = [0x71 | 0x80, 1],
222             14 => last_bytes = [0x61 | 0x80, 1],
223             13 => last_bytes = [0x51 | 0x80, 1],
224             12 => last_bytes = [0x41 | 0x80, 1],
225             11 => last_bytes = [0x31 | 0x80, 1],
226             10 => last_bytes = [0x21 | 0x80, 1],
227             _ => {assert_eq!(log_window_size, 17); last_bytes = [0x1 | 0x80, 1];} // 17
228         }
229         last_bytes_len = 2;
230     }
231     BroCatli {
232       last_bytes: last_bytes,
233       last_bytes_len: last_bytes_len,
234       last_byte_bit_offset: 0,
235       last_byte_sanitized: false,
236       any_bytes_emitted: false,
237       new_stream_pending: None,
238       window_size:log_window_size,
239     }
240   }
241 
new_brotli_file(&mut self)242   pub fn new_brotli_file(&mut self) {
243     self.new_stream_pending = Some(NewStreamData::new());
244   }
flush_previous_stream(&mut self, out_bytes: &mut [u8], out_offset: &mut usize) -> BroCatliResult245   fn flush_previous_stream(&mut self, out_bytes: &mut [u8], out_offset: &mut usize) -> BroCatliResult {
246     if !self.last_byte_sanitized { // if the previous stream hasn't had the last metablock (bit 1,1) sanitized
247       if self.last_bytes_len == 0 { // first stream or otherwise sanitized
248         self.last_byte_sanitized = true;
249         return BroCatliResult::Success;
250       }
251       // create a 16 bit integer with the last 2 bytes of data
252       let mut last_bytes = self.last_bytes[0] as u16 + ((self.last_bytes[1] as u16) << 8);
253       let max = self.last_bytes_len * 8;
254       let mut index = max - 1;
255       for i in 0..max {
256         index = max - 1 - i;
257         if ((1<<index) & last_bytes) != 0 {
258           break; // find the highest set bit
259         }
260       }
261       if index == 0 { // if the bit is too low, return failure, since both bits could not possibly have been set
262         return BroCatliResult::BrotliFileNotCraftedForAppend;
263       }
264       if (last_bytes >> (index - 1)) != 3 { // last two bits need to be set for the final metablock
265         return BroCatliResult::BrotliFileNotCraftedForAppend;
266       }
267       index -= 1; // discard the final two bits
268       last_bytes &= (1 << index) - 1; // mask them out
269       self.last_bytes[0] = last_bytes as u8 & 0xff; // reset the last_bytes pair
270       self.last_bytes[1] = (last_bytes >> 8) as u8 & 0xff;
271       if index >= 8 { // if both bits and one useful bit were in the second block, then write that
272         if out_bytes.len() > *out_offset {
273           out_bytes[*out_offset] = self.last_bytes[0];
274           self.last_bytes[0] = self.last_bytes[1];
275           *out_offset += 1;
276           self.any_bytes_emitted = true;
277           index -= 8;
278           self.last_bytes_len -= 1;
279         } else {
280           return BroCatliResult::NeedsMoreOutput;
281         }
282       }
283       self.last_byte_bit_offset = index;
284       assert!(index < 8);
285       self.last_byte_sanitized = true;
286     }
287     BroCatliResult::Success
288   }
289 
shift_and_check_new_stream_header(&mut self, mut new_stream_pending: NewStreamData, out_bytes: &mut [u8], out_offset: &mut usize) -> BroCatliResult290   fn shift_and_check_new_stream_header(&mut self, mut new_stream_pending: NewStreamData, out_bytes: &mut [u8], out_offset: &mut usize) -> BroCatliResult {
291     if new_stream_pending.num_bytes_written.is_none() {
292       let (window_size, window_offset) = if let Ok(results) = parse_window_size(
293         &new_stream_pending.bytes_so_far[..usize::from(new_stream_pending.num_bytes_read)],
294       ) {
295         results
296       } else {
297         return BroCatliResult::InvalidWindowSize;
298       };
299       if self.window_size == 0 { // parse window size and just copy everything
300         self.window_size = window_size;
301         assert_eq!(self.last_byte_bit_offset, 0); // we are first stream
302         out_bytes[*out_offset] = new_stream_pending.bytes_so_far[0];
303         new_stream_pending.num_bytes_written = Some(1);
304         self.any_bytes_emitted = true;
305         *out_offset += 1;
306       } else {
307         if window_size > self.window_size {
308           return BroCatliResult::WindowSizeLargerThanPreviousFile;
309         }
310         let mut realigned_header:[u8;NUM_STREAM_HEADER_BYTES + 1] = [self.last_bytes[0],
311                                                                     0,0,0,0,0,
312         ];
313         let varlen_offset = if let Ok(voffset) = detect_varlen_offset(
314           &new_stream_pending.bytes_so_far[..usize::from(new_stream_pending.num_bytes_read)],
315         ) {
316           voffset
317         } else {
318           return BroCatliResult::BrotliFileNotCraftedForConcatenation;
319         };
320         let mut bytes_so_far = 0u64;
321         for index in 0..usize::from(new_stream_pending.num_bytes_read) {
322           bytes_so_far |= u64::from(new_stream_pending.bytes_so_far[index]) << (index * 8);
323         }
324         bytes_so_far >>= window_offset; // mask out the window size
325         bytes_so_far &= (1u64 << (varlen_offset - window_offset)) - 1;
326         let var_len_bytes = ((usize::from(varlen_offset - window_offset) + 7) / 8);
327         for byte_index in 0..var_len_bytes {
328           let cur_byte = (bytes_so_far >> (byte_index *8));
329           realigned_header[byte_index] |= ((cur_byte & ((1 << (8 - self.last_byte_bit_offset)) - 1)) << self.last_byte_bit_offset) as u8;
330           realigned_header[byte_index + 1] = (cur_byte >> (8 - self.last_byte_bit_offset)) as u8;
331         }
332         let whole_byte_destination = ((usize::from(self.last_byte_bit_offset) + varlen_offset - window_offset) + 7) / 8;
333         let whole_byte_source = (varlen_offset + 7) / 8;
334         let num_whole_bytes_to_copy = usize::from(new_stream_pending.num_bytes_read) - whole_byte_source;
335         for aligned_index in 0..num_whole_bytes_to_copy {
336           realigned_header[whole_byte_destination + aligned_index] = new_stream_pending.bytes_so_far[whole_byte_source + aligned_index];
337         }
338         out_bytes[*out_offset] = realigned_header[0];
339         self.any_bytes_emitted = true;
340         *out_offset += 1;
341         // subtract one since that has just been written out and we're only copying realigned_header[1..]
342         new_stream_pending.num_bytes_read = (whole_byte_destination + num_whole_bytes_to_copy) as u8 - 1;
343         new_stream_pending.num_bytes_written = Some(0);
344         new_stream_pending.bytes_so_far.clone_from_slice(&realigned_header[1..]);
345       }
346     } else {
347       assert!(self.window_size != 0);
348     }
349     let to_copy = core::cmp::min(out_bytes.len() - *out_offset,
350                                  usize::from(new_stream_pending.num_bytes_read - new_stream_pending.num_bytes_written.unwrap()));
351     out_bytes.split_at_mut(*out_offset).1.split_at_mut(to_copy).0.clone_from_slice(
352       &new_stream_pending.bytes_so_far.split_at(usize::from(new_stream_pending.num_bytes_written.unwrap())).1.split_at(to_copy).0);
353     *out_offset += to_copy;
354     if to_copy != 0 {
355       self.any_bytes_emitted = true;
356     }
357     new_stream_pending.num_bytes_written = Some((new_stream_pending.num_bytes_written.unwrap() + to_copy as u8));
358     if new_stream_pending.num_bytes_written.unwrap() != new_stream_pending.num_bytes_read {
359       self.new_stream_pending = Some(new_stream_pending);
360       return BroCatliResult::NeedsMoreOutput;
361     }
362     self.new_stream_pending = None;
363     self.last_byte_sanitized = false;
364     self.last_byte_bit_offset = 0;
365     self.last_bytes_len = 0;
366     self.last_bytes = [0,0];
367     //now unwrite from the stream, since the last byte may need to be adjusted to be EOF
368     *out_offset -= 1;
369     self.last_bytes[0] = out_bytes[*out_offset];
370     self.last_bytes_len = 1;
371     BroCatliResult::Success
372   }
stream(&mut self, in_bytes: &[u8], in_offset: &mut usize, out_bytes: &mut [u8], out_offset: &mut usize) -> BroCatliResult373   pub fn stream(&mut self, in_bytes: &[u8], in_offset: &mut usize, out_bytes: &mut [u8], out_offset: &mut usize) -> BroCatliResult {
374     if let Some(mut new_stream_pending) = self.new_stream_pending.clone() {
375       let flush_result = self.flush_previous_stream(out_bytes, out_offset);
376       if let BroCatliResult::Success = flush_result {
377         if usize::from(new_stream_pending.num_bytes_read) < new_stream_pending.bytes_so_far.len() {
378           {
379             let dst = &mut new_stream_pending.bytes_so_far[usize::from(new_stream_pending.num_bytes_read)..];
380             let to_copy = core::cmp::min(dst.len(), in_bytes.len() - *in_offset);
381             dst[..to_copy].clone_from_slice(in_bytes.split_at(*in_offset).1.split_at(to_copy).0);
382             *in_offset += to_copy;
383             new_stream_pending.num_bytes_read += to_copy as u8;
384           }
385           self.new_stream_pending = Some(new_stream_pending); // write back changes
386         }
387         if !new_stream_pending.sufficient() {
388           return BroCatliResult::NeedsMoreInput;
389         }
390         if out_bytes.len() == *out_offset {
391           return BroCatliResult::NeedsMoreOutput;
392         }
393         let shift_result = self.shift_and_check_new_stream_header(new_stream_pending, out_bytes, out_offset);
394         if let BroCatliResult::Success = shift_result {
395         } else {
396           return shift_result;
397         }
398       } else {
399         return flush_result;
400       }
401       if *out_offset == out_bytes.len() {
402         return BroCatliResult::NeedsMoreOutput; // need to be able to write at least one byte of data to make progress
403       }
404     }
405     assert!(self.new_stream_pending.is_none());// this should have been handled above
406     if self.last_bytes_len != 2 {
407       if out_bytes.len() == *out_offset{
408         return BroCatliResult::NeedsMoreOutput;
409       }
410       if in_bytes.len() == *in_offset {
411         return BroCatliResult::NeedsMoreInput;
412       }
413       self.last_bytes[usize::from(self.last_bytes_len)] = in_bytes[*in_offset];
414       *in_offset += 1;
415       self.last_bytes_len += 1;
416       if self.last_bytes_len != 2 {
417         if out_bytes.len() == *out_offset{
418           return BroCatliResult::NeedsMoreOutput;
419         }
420         if in_bytes.len() == *in_offset {
421           return BroCatliResult::NeedsMoreInput;
422         }
423         self.last_bytes[usize::from(self.last_bytes_len)] = in_bytes[*in_offset];
424         self.last_bytes_len += 1;
425         *in_offset += 1;
426       }
427     }
428     if out_bytes.len() == *out_offset{
429       return BroCatliResult::NeedsMoreOutput;
430     }
431     if in_bytes.len() == *in_offset{
432       return BroCatliResult::NeedsMoreInput;
433     }
434     let mut to_copy = core::cmp::min(out_bytes.len() - *out_offset,
435                                      in_bytes.len() - *in_offset);
436     assert!(to_copy != 0);
437     if to_copy == 1 {
438       out_bytes[*out_offset] = self.last_bytes[0];
439       self.last_bytes[0] = self.last_bytes[1];
440       self.last_bytes[1] = in_bytes[*in_offset];
441       *in_offset += 1;
442       *out_offset += 1;
443       if *out_offset == out_bytes.len() {
444         return BroCatliResult::NeedsMoreOutput;
445       }
446       return BroCatliResult::NeedsMoreInput;
447     }
448     out_bytes.split_at_mut(*out_offset).1.split_at_mut(2).0.clone_from_slice(&self.last_bytes[..]);
449     *out_offset += 2;
450     let (new_in_offset, last_two) = in_bytes.split_at(*in_offset).1.split_at(to_copy).0.split_at(to_copy-2);
451     self.last_bytes.clone_from_slice(last_two);
452     *in_offset += 2; // add this after the clone since we grab the last 2 bytes, not the first
453     to_copy -= 2;
454       out_bytes.split_at_mut(*out_offset).1.split_at_mut(to_copy).0.clone_from_slice(
455           new_in_offset);
456     *out_offset += to_copy;
457     *in_offset += to_copy;
458     if *out_offset == out_bytes.len() {
459       return BroCatliResult::NeedsMoreOutput;
460     }
461     return BroCatliResult::NeedsMoreInput;
462   }
append_eof_metablock_to_last_bytes(&mut self)463   fn append_eof_metablock_to_last_bytes(&mut self) {
464     assert!(self.last_byte_sanitized);
465     let mut last_bytes = self.last_bytes[0] as u16 | ((self.last_bytes[1] as u16) << 8);
466     let bit_end = (self.last_bytes_len - 1) * 8 + self.last_byte_bit_offset;
467     last_bytes |= 3 << bit_end;
468     self.last_bytes[0] = last_bytes as u8 & 0xff;
469     self.last_bytes[1] = (last_bytes >> 8) as u8 & 0xff;
470     self.last_byte_sanitized = false;
471     self.last_byte_bit_offset += 2;
472     if self.last_byte_bit_offset >= 8 {
473       self.last_byte_bit_offset -= 8;
474       self.last_bytes_len += 1;
475     }
476   }
finish(&mut self, out_bytes: &mut [u8], out_offset: &mut usize) -> BroCatliResult477   pub fn finish(&mut self, out_bytes: &mut [u8], out_offset: &mut usize) -> BroCatliResult {
478        if self.last_byte_sanitized && self.last_bytes_len != 0 {
479            self.append_eof_metablock_to_last_bytes();
480        }
481        while self.last_bytes_len != 0 {
482            if *out_offset == out_bytes.len() {
483 
484              return BroCatliResult::NeedsMoreOutput;
485            }
486            out_bytes[*out_offset] = self.last_bytes[0];
487            *out_offset += 1;
488            self.last_bytes_len -= 1;
489            self.last_bytes[0] = self.last_bytes[1];
490            self.any_bytes_emitted = true;
491        }
492        if !self.any_bytes_emitted {
493            if out_bytes.len() == *out_offset{
494                return BroCatliResult::NeedsMoreOutput;
495            }
496            self.any_bytes_emitted = true;
497            out_bytes[*out_offset] = b';';
498            *out_offset += 1;
499        }
500        BroCatliResult::Success
501    }
502 }
503 
504 mod test {
505     #[cfg(test)]
506     use super::{BroCatli};
507     #[test]
test_deserialization()508     fn test_deserialization() {
509         let broccoli = BroCatli{
510             new_stream_pending:Some(super::NewStreamData {
511                 bytes_so_far: [0x33; super::NUM_STREAM_HEADER_BYTES],
512                 num_bytes_read: 16,
513                 num_bytes_written: Some(3),
514             }),
515             last_bytes: [0x45, 0x46],
516             last_bytes_len: 1,
517             last_byte_sanitized: true,
518             any_bytes_emitted: false,
519             last_byte_bit_offset: 7,
520             window_size:22,
521         };
522         let mut buffer = [0u8;248];
523         broccoli.serialize_to_buffer(&mut buffer[..]).unwrap();
524         let bc = BroCatli::deserialize_from_buffer(&buffer[..]).unwrap();
525         assert_eq!(broccoli.last_bytes, bc.last_bytes);
526         assert_eq!(broccoli.last_bytes_len, bc.last_bytes_len);
527         assert_eq!(broccoli.last_byte_sanitized, bc.last_byte_sanitized);
528         assert_eq!(broccoli.last_byte_bit_offset, bc.last_byte_bit_offset);
529         assert_eq!(broccoli.window_size, bc.window_size);
530         assert_eq!(broccoli.new_stream_pending.unwrap().bytes_so_far,
531                    bc.new_stream_pending.unwrap().bytes_so_far);
532         assert_eq!(broccoli.new_stream_pending.unwrap().num_bytes_read,
533                    bc.new_stream_pending.unwrap().num_bytes_read);
534         assert_eq!(broccoli.new_stream_pending.unwrap().num_bytes_written,
535                    bc.new_stream_pending.unwrap().num_bytes_written);
536     }
537     #[test]
test_deserialization_any_written()538     fn test_deserialization_any_written() {
539         let broccoli = BroCatli{
540             new_stream_pending:Some(super::NewStreamData {
541                 bytes_so_far: [0x33; super::NUM_STREAM_HEADER_BYTES],
542                 num_bytes_read: 16,
543                 num_bytes_written: Some(3),
544             }),
545             last_bytes: [0x45, 0x46],
546             last_bytes_len: 1,
547             last_byte_sanitized: true,
548             any_bytes_emitted: true,
549             last_byte_bit_offset: 7,
550             window_size:22,
551         };
552         let mut buffer = [0u8;248];
553         broccoli.serialize_to_buffer(&mut buffer[..]).unwrap();
554         let bc = BroCatli::deserialize_from_buffer(&buffer[..]).unwrap();
555         assert_eq!(broccoli.last_bytes, bc.last_bytes);
556         assert_eq!(broccoli.last_bytes_len, bc.last_bytes_len);
557         assert_eq!(broccoli.last_byte_sanitized, bc.last_byte_sanitized);
558         assert_eq!(broccoli.last_byte_bit_offset, bc.last_byte_bit_offset);
559         assert_eq!(broccoli.window_size, bc.window_size);
560         assert_eq!(broccoli.new_stream_pending.unwrap().bytes_so_far,
561                    bc.new_stream_pending.unwrap().bytes_so_far);
562         assert_eq!(broccoli.new_stream_pending.unwrap().num_bytes_read,
563                    bc.new_stream_pending.unwrap().num_bytes_read);
564         assert_eq!(broccoli.new_stream_pending.unwrap().num_bytes_written,
565                    bc.new_stream_pending.unwrap().num_bytes_written);
566     }
567     #[test]
test_serialization()568     fn test_serialization() {
569         let mut buffer = [0u8;248];
570         let mut broccoli = BroCatli::deserialize_from_buffer(&buffer).unwrap();
571         let mut buffer2 = [0u8;248];
572         broccoli.serialize_to_buffer(&mut buffer2[..]).unwrap();
573         assert_eq!(&buffer[..], &buffer2[..]);
574         for (index, item) in buffer.iter_mut().enumerate() {
575             *item = index as u8;
576         }
577         broccoli = BroCatli::deserialize_from_buffer(&buffer).unwrap();
578         broccoli.serialize_to_buffer(&mut buffer2[..]).unwrap();
579         broccoli = BroCatli::deserialize_from_buffer(&buffer2).unwrap();
580         for (_index, item) in buffer.iter_mut().enumerate() {
581             *item = 0;
582         }
583         broccoli.serialize_to_buffer(&mut buffer[..]).unwrap();
584         assert_eq!(&buffer[..], &buffer2[..]);
585         for (index, item) in buffer.iter_mut().enumerate() {
586             *item = 0xff ^ index as u8;
587         }
588         broccoli = BroCatli::deserialize_from_buffer(&buffer).unwrap();
589         broccoli.serialize_to_buffer(&mut buffer2[..]).unwrap();
590         broccoli = BroCatli::deserialize_from_buffer(&buffer2).unwrap();
591         for (_index, item) in buffer.iter_mut().enumerate() {
592             *item = 0;
593         }
594         broccoli.serialize_to_buffer(&mut buffer[..]).unwrap();
595         assert_eq!(&buffer[..], &buffer2[..]);
596     }
597     #[test]
test_cat_empty_stream()598     fn test_cat_empty_stream() {
599         let empty_catable = [b';'];
600         let mut bcat = super::BroCatli::default();
601         let mut in_offset = 0usize;
602         let mut out_bytes = [0u8;32];
603         let mut out_offset = 0usize;
604         bcat.new_brotli_file();
605         let mut res = bcat.stream(&empty_catable[..],
606                               &mut in_offset,
607                               &mut out_bytes[..],
608                               &mut out_offset);
609         assert_eq!(res, super::BroCatliResult::NeedsMoreInput);
610         bcat.new_brotli_file();
611         in_offset = 0;
612         res = bcat.stream(&empty_catable[..],
613                               &mut in_offset,
614                               &mut out_bytes[..],
615                               &mut out_offset);
616         assert_eq!(res, super::BroCatliResult::NeedsMoreInput);
617         res = bcat.finish(&mut out_bytes[..],
618                           &mut out_offset);
619         assert_eq!(res, super::BroCatliResult::Success);
620         assert!(out_offset != 0);
621         assert_eq!(&out_bytes[..out_offset], &[b';']);
622     }
623 }
624