1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4#[macro_use]
5extern crate thiserror;
6mod bindings;
7use bindings::*;
8
9#[cfg(not(target_family = "wasm"))]
10use libc::*;
11#[cfg(not(target_family = "wasm"))]
12use std::ffi::{CString};
13use std::ffi::{c_void, CStr};
14
15#[cfg(target_family = "wasm")]
16type c_longlong = i64;
17
18pub fn version() -> &'static CStr {
19 unsafe {
20 CStr::from_ptr(ZSTD_versionString())
21 }
22}
23
24pub fn out_size() -> size_t {
25 unsafe { ZSTD_DStreamOutSize() }
26}
27
28pub struct SeekableCStream {
30 p: *mut ZSTD_seekable_CStream,
31}
32
33pub struct CStream {
35 p: *mut ZSTD_CStream,
36}
37
38pub struct FrameLog {
40 p: *mut ZSTD_frameLog,
41}
42
43#[cfg(not(target_family = "wasm"))]
45pub struct Seekable<'a, R> {
46 p: *mut ZSTD_seekable,
47 b: *mut R,
48 f: *mut libc::FILE,
49 marker: std::marker::PhantomData<&'a R>,
50}
51
52#[cfg(target_family = "wasm")]
53pub struct Seekable<'a, R> {
54 p: *mut ZSTD_seekable,
55 b: *mut R,
56 f: *mut std::ffi::c_void,
57 marker: std::marker::PhantomData<&'a R>,
58}
59
60unsafe impl<R> Send for Seekable<'static, R> {}
61unsafe impl Send for SeekableCStream {}
62unsafe impl Send for FrameLog {}
63unsafe impl<D: Dst> Send for CompressedFrame<D> {}
64
65#[derive(Error)]
66pub enum Error {
67 Null,
68 CouldNotOpenFile(String),
69 ZSTD(size_t),
70 Io(#[from] std::io::Error),
71}
72
73impl std::fmt::Debug for Error {
74 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
75 match *self {
76 Error::Null => write!(fmt, "Null"),
77 Error::Io(ref e) => e.fmt(fmt),
78 Error::CouldNotOpenFile(ref f) => write!(fmt, "Could not open {}", f),
79 Error::ZSTD(r) => unsafe {
80 let error = CStr::from_ptr(ZSTD_getErrorName(r));
81 write!(fmt, "ZSTD({:?})", error)
82 },
83 }
84 }
85}
86
87impl std::fmt::Display for Error {
88 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
89 write!(fmt, "{:?}", self)
90 }
91}
92
93impl Drop for SeekableCStream {
94 fn drop(&mut self) {
95 unsafe {
96 if !self.p.is_null() {
97 ZSTD_seekable_freeCStream(self.p);
98 self.p = std::ptr::null_mut();
99 }
100 }
101 }
102}
103
104impl Drop for CStream {
105 fn drop(&mut self) {
106 unsafe {
107 if !self.p.is_null() {
108 ZSTD_freeCStream(self.p);
109 self.p = std::ptr::null_mut();
110 }
111 }
112 }
113}
114
115
116impl<'a, R> Drop for Seekable<'a, R> {
117 fn drop(&mut self) {
118 unsafe {
119 if !self.p.is_null() {
120 ZSTD_seekable_free(self.p);
121 self.p = std::ptr::null_mut();
122 }
123 if !self.f.is_null() {
124 #[cfg(target_family = "wasm")]
125 fn fclose(_: *mut c_void) {}
126 fclose(self.f);
127 self.f = std::ptr::null_mut();
128 }
129 if !self.b.is_null() {
130 let b: Box<R> = Box::from_raw(self.b);
131 std::mem::drop(b);
132 self.b = std::ptr::null_mut();
133 }
134 }
135 }
136}
137
138impl Drop for FrameLog {
139 fn drop(&mut self) {
140 unsafe {
141 if !self.p.is_null() {
142 ZSTD_seekable_freeFrameLog(self.p);
143 self.p = std::ptr::null_mut()
144 }
145 }
146 }
147}
148
149unsafe extern "C" fn zstd_seekable_read<R: std::io::Read + std::io::Seek>(
150 opaque: *mut c_void,
151 buffer: *mut c_void,
152 n: size_t,
153) -> c_int {
154 let mut b: Box<R> = Box::from_raw(opaque as *mut R);
155 let s = std::slice::from_raw_parts_mut(buffer as *mut u8, n as usize);
156 let result = if b.read_exact(s).is_ok() { 0 } else { 1 };
157 std::mem::forget(b);
158 result
159}
160
161#[cfg(target_family = "wasm")]
162const SEEK_SET: c_int = 0;
163#[cfg(target_family = "wasm")]
164const SEEK_CUR: c_int = 1;
165unsafe extern "C" fn zstd_seekable_seek<R: std::io::Read + std::io::Seek>(
169 opaque: *mut c_void,
170 offset: c_longlong,
171 origin: c_int,
172) -> c_int {
173 let mut b: Box<R> = Box::from_raw(opaque as *mut R);
174 use std::io::SeekFrom;
175 let origin = if origin == SEEK_SET {
176 SeekFrom::Start(offset as u64)
177 } else if origin == SEEK_CUR {
178 SeekFrom::Current(offset as i64)
179 } else {
180 SeekFrom::End(offset as i64)
181 };
182 let result = if b.seek(origin).is_ok() { 0 } else { 1 };
183 std::mem::forget(b);
184 result
185}
186
187impl SeekableCStream {
188 pub fn new(level: usize, frame_size: usize) -> Result<Self, Error> {
190 unsafe {
191 let p = ZSTD_seekable_createCStream();
192 if p.is_null() {
193 return Err(Error::Null);
194 }
195 let result = ZSTD_seekable_initCStream(p, level as c_int, 1, frame_size as c_uint);
196 if ZSTD_isError(result) != 0 {
197 return Err(Error::ZSTD(result));
198 }
199 Ok(SeekableCStream { p })
200 }
201 }
202 pub fn compress(&mut self, output: &mut [u8], input: &[u8]) -> Result<(usize, usize), Error> {
204 unsafe {
205 let mut input = ZSTD_inBuffer {
206 src: input.as_ptr() as *const c_void,
207 size: input.len() as size_t,
208 pos: 0,
209 };
210 let mut output = ZSTD_outBuffer {
211 dst: output.as_mut_ptr() as *mut c_void,
212 size: output.len() as size_t,
213 pos: 0,
214 };
215 let result = ZSTD_seekable_compressStream(self.p, &mut output, &mut input);
216 if ZSTD_isError(result) != 0 {
217 return Err(Error::ZSTD(result));
218 }
219 Ok((output.pos as usize, input.pos as usize))
220 }
221 }
222
223 pub fn end_stream(&mut self, output: &mut [u8]) -> Result<usize, Error> {
225 unsafe {
226 let mut output = ZSTD_outBuffer {
227 dst: output.as_mut_ptr() as *mut c_void,
228 size: output.len() as size_t,
229 pos: 0,
230 };
231 let result = ZSTD_seekable_endStream(self.p, &mut output);
232 if ZSTD_isError(result) != 0 {
233 return Err(Error::ZSTD(result));
234 }
235 Ok(output.pos as usize)
236 }
237 }
238}
239
240impl CStream {
241 pub fn new(level: usize) -> Result<Self, Error> {
242 unsafe {
243 let p = ZSTD_createCStream();
244 if p.is_null() {
245 return Err(Error::Null);
246 }
247 let result = ZSTD_initCStream(p, level as c_int);
248 if ZSTD_isError(result) != 0 {
249 return Err(Error::ZSTD(result));
250 }
251 Ok(CStream { p })
252 }
253 }
254
255 pub fn in_size() -> usize {
256 unsafe { ZSTD_CStreamInSize() as usize }
257 }
258
259 pub fn out_size() -> usize {
260 unsafe { ZSTD_CStreamOutSize() as usize }
261 }
262
263 pub fn compress(
265 &mut self,
266 output: &mut [u8],
267 input: &[u8],
268 ) -> Result<(usize, usize, usize), Error> {
269 unsafe {
270 let mut input = ZSTD_inBuffer {
271 src: input.as_ptr() as *const c_void,
272 size: input.len() as size_t,
273 pos: 0,
274 };
275 let mut output = ZSTD_outBuffer {
276 dst: output.as_mut_ptr() as *mut c_void,
277 size: output.len() as size_t,
278 pos: 0,
279 };
280 let result = ZSTD_compressStream(self.p, &mut output, &mut input);
281 Ok((output.pos as usize, input.pos as usize, result as usize))
282 }
283 }
284
285 pub fn compress2(
286 &mut self,
287 output: &mut [u8],
288 input: &[u8],
289 op: EndDirective,
290 ) -> Result<(usize, usize, usize), Error> {
291 unsafe {
292 let mut input = ZSTD_inBuffer {
293 src: input.as_ptr() as *const c_void,
294 size: input.len() as size_t,
295 pos: 0,
296 };
297 let mut output = ZSTD_outBuffer {
298 dst: output.as_mut_ptr() as *mut c_void,
299 size: output.len() as size_t,
300 pos: 0,
301 };
302 let result = ZSTD_compressStream2(self.p, &mut output, &mut input, op as ZSTD_EndDirective);
303 Ok((output.pos as usize, input.pos as usize, result as usize))
304 }
305 }
306
307 pub fn flush(&mut self, output: &mut [u8]) -> Result<(usize, usize), Error> {
308 unsafe {
309 let mut output = ZSTD_outBuffer {
310 dst: output.as_mut_ptr() as *mut c_void,
311 size: output.len() as size_t,
312 pos: 0,
313 };
314 let result = ZSTD_flushStream(self.p, &mut output);
315 Ok((output.pos as usize, result as usize))
316 }
317 }
318
319 pub fn end(&mut self, output: &mut [u8]) -> Result<usize, Error> {
321 unsafe {
322 let mut output = ZSTD_outBuffer {
323 dst: output.as_mut_ptr() as *mut c_void,
324 size: output.len() as size_t,
325 pos: 0,
326 };
327 let result = ZSTD_endStream(self.p, &mut output);
328 if ZSTD_isError(result) != 0 {
329 return Err(Error::ZSTD(result));
330 }
331 Ok(output.pos as usize)
332 }
333 }
334}
335
336pub enum EndDirective {
337 Continue = 0,
338 Flush = 1,
339 End = 2,
340}
341
342pub struct DStream {
343 p: *mut ZSTD_DStream,
344}
345
346unsafe impl Send for DStream {}
347
348impl Drop for DStream {
349 fn drop(&mut self) {
350 unsafe {
351 ZSTD_freeDStream(self.p);
352 self.p = std::ptr::null_mut();
353 }
354 }
355}
356
357impl DStream {
358 pub fn new() -> Result<Self, Error> {
359 unsafe {
360 let p = ZSTD_createDStream();
361 if p.is_null() {
362 return Err(Error::Null);
363 }
364 let result = ZSTD_initDStream(p);
365 if ZSTD_isError(result) != 0 {
366 return Err(Error::ZSTD(result));
367 }
368 Ok(DStream { p })
369 }
370 }
371
372 pub fn decompress(&mut self, output: &mut [u8], input: &[u8]) -> Result<(usize, usize), Error> {
373 unsafe {
374 let mut input = ZSTD_inBuffer {
375 src: input.as_ptr() as *const c_void,
376 size: input.len() as size_t,
377 pos: 0,
378 };
379 let mut output = ZSTD_outBuffer {
380 dst: output.as_mut_ptr() as *mut c_void,
381 size: output.len() as size_t,
382 pos: 0,
383 };
384 let _result = ZSTD_decompressStream(self.p, &mut output, &mut input);
385 Ok((output.pos as usize, input.pos as usize))
386 }
387 }
388}
389
390impl<'a> Seekable<'a, ()> {
391 pub fn init_buf(input: &'a [u8]) -> Result<Self, Error> {
393 unsafe {
394 let p = ZSTD_seekable_create();
395 if p.is_null() {
396 return Err(Error::Null);
397 }
398 let result =
399 ZSTD_seekable_initBuff(p, input.as_ptr() as *const c_void, input.len() as size_t);
400 if ZSTD_isError(result) != 0 {
401 return Err(Error::ZSTD(result));
402 }
403 Ok(Seekable {
404 p,
405 f: std::ptr::null_mut(),
406 b: std::ptr::null_mut(),
407 marker: std::marker::PhantomData,
408 })
409 }
410 }
411
412 #[cfg(not(target_family = "wasm"))]
414 pub fn init_file(name_: &str) -> Result<Self, Error> {
415 unsafe {
416 let name = CString::new(name_).unwrap();
417 let f: *mut libc::FILE = fopen(name.as_ptr(), "rb\0".as_ptr() as *const c_char);
418 if f.is_null() {
419 return Err(Error::CouldNotOpenFile(name_.to_string()));
420 }
421 let p = ZSTD_seekable_create();
422 if p.is_null() {
423 return Err(Error::Null);
424 }
425 let result = ZSTD_seekable_initFile(p, f as *mut FILE);
426 if ZSTD_isError(result) != 0 {
427 return Err(Error::ZSTD(result));
428 }
429 Ok(Seekable {
430 p,
431 f,
432 b: std::ptr::null_mut(),
433 marker: std::marker::PhantomData,
434 })
435 }
436 }
437}
438
439impl<'a, R: std::io::Read + std::io::Seek> Seekable<'a, R> {
440 pub fn init(r: Box<R>) -> Result<Self, Error> {
442 unsafe {
443 let p = ZSTD_seekable_create();
444 if p.is_null() {
445 return Err(Error::Null);
446 }
447 let opaque = Box::into_raw(r) as *mut R;
448 let adv = ZSTD_seekable_customFile {
449 opaque: opaque as *mut c_void,
450 read: Some(zstd_seekable_read::<R>),
451 seek: Some(zstd_seekable_seek::<R>),
452 };
453 let result = ZSTD_seekable_initAdvanced(p, adv);
454 if ZSTD_isError(result) != 0 {
455 return Err(Error::ZSTD(result));
456 }
457 Ok(Seekable {
458 p,
459 f: std::ptr::null_mut(),
460 b: opaque,
461 marker: std::marker::PhantomData,
462 })
463 }
464 }
465
466 pub fn into_inner(self) -> Box<R> {
467 unsafe { Box::from_raw(self.b) }
468 }
469}
470
471impl<'a, R> Seekable<'a, R> {
472 pub fn decompress(&mut self, out: &mut [u8], offset: u64) -> Result<usize, Error> {
478 unsafe {
479 let result = ZSTD_seekable_decompress(
480 self.p,
481 out.as_mut_ptr() as *mut c_void,
482 out.len() as size_t,
483 offset,
484 );
485 if ZSTD_isError(result) != 0 {
486 return Err(Error::ZSTD(result));
487 }
488 Ok(result as usize)
489 }
490 }
491
492 pub fn get_num_frames(&self) -> usize {
494 unsafe { ZSTD_seekable_getNumFrames(self.p) as usize }
495 }
496 pub fn get_frame_compressed_offset(&self, frame_index: usize) -> c_ulonglong {
498 unsafe { ZSTD_seekable_getFrameCompressedOffset(self.p, frame_index as c_uint) }
499 }
500 pub fn get_frame_compressed_size(&self, frame_index: usize) -> usize {
502 unsafe { ZSTD_seekable_getFrameCompressedSize(self.p, frame_index as c_uint) as usize }
503 }
504 pub fn get_frame_decompressed_offset(&self, frame_index: usize) -> u64 {
506 unsafe { ZSTD_seekable_getFrameDecompressedOffset(self.p, frame_index as c_uint) }
507 }
508 pub fn get_frame_decompressed_size(&self, frame_index: usize) -> usize {
510 unsafe { ZSTD_seekable_getFrameDecompressedSize(self.p, frame_index as c_uint) as usize }
511 }
512 pub fn decompress_frame(&mut self, dest: &mut [u8], index: usize) -> usize {
514 unsafe {
515 ZSTD_seekable_decompressFrame(
516 self.p,
517 dest.as_mut_ptr() as *mut c_void,
518 dest.len() as size_t,
519 index as c_uint,
520 ) as usize
521 }
522 }
523 pub fn seekable_offset_to_frame_index(&mut self, offset: u64) -> usize {
525 unsafe { ZSTD_seekable_offsetToFrameIndex(self.p, offset) as usize }
526 }
527}
528
529pub trait Dst: Send {
530 fn as_mut_ptr(&mut self) -> *mut u8;
531 fn as_slice(&self) -> &[u8];
532 fn len(&self) -> usize;
533 fn new() -> Self;
534}
535impl Dst for [u8; 256] {
536 fn as_mut_ptr(&mut self) -> *mut u8 {
537 self.as_mut().as_mut_ptr()
538 }
539 fn as_slice(&self) -> &[u8] {
540 self.as_ref()
541 }
542 fn len(&self) -> usize {
543 256
544 }
545 fn new() -> Self {
546 [0; 256]
547 }
548}
549impl Dst for [u8; 512] {
550 fn as_mut_ptr(&mut self) -> *mut u8 {
551 self.as_mut().as_mut_ptr()
552 }
553 fn as_slice(&self) -> &[u8] {
554 self.as_ref()
555 }
556 fn len(&self) -> usize {
557 512
558 }
559 fn new() -> Self {
560 [0; 512]
561 }
562}
563impl Dst for [u8; 1024] {
564 fn as_mut_ptr(&mut self) -> *mut u8 {
565 self.as_mut().as_mut_ptr()
566 }
567 fn as_slice(&self) -> &[u8] {
568 self.as_ref()
569 }
570 fn len(&self) -> usize {
571 1024
572 }
573 fn new() -> Self {
574 [0; 1024]
575 }
576}
577impl Dst for [u8; 2048] {
578 fn as_mut_ptr(&mut self) -> *mut u8 {
579 self.as_mut().as_mut_ptr()
580 }
581 fn as_slice(&self) -> &[u8] {
582 self.as_ref()
583 }
584 fn len(&self) -> usize {
585 2048
586 }
587 fn new() -> Self {
588 [0; 2048]
589 }
590}
591impl Dst for [u8; 4096] {
592 fn as_mut_ptr(&mut self) -> *mut u8 {
593 self.as_mut().as_mut_ptr()
594 }
595 fn as_slice(&self) -> &[u8] {
596 self.as_ref()
597 }
598 fn len(&self) -> usize {
599 4096
600 }
601 fn new() -> Self {
602 [0; 4096]
603 }
604}
605
606pub struct CompressedFrame<D: Dst> {
607 src_size: size_t,
608 dst_size: size_t,
609 checksum: c_uint,
610 dst: D,
611}
612
613impl<D: Dst> CompressedFrame<D> {
614 fn as_slice(&self) -> &[u8] {
615 &self.dst.as_slice()[..self.dst_size as usize]
616 }
617}
618
619extern "C" {
620 fn xxh64(src: *const u8, len: c_int) -> c_uint;
621}
622
623fn compress_frame<D: Dst>(
624 src_ptr: *const u8,
625 src_len: size_t,
626 level: usize,
627) -> Result<CompressedFrame<D>, Error> {
628 unsafe {
629 let mut dst = D::new();
630 let checksum = xxh64(src_ptr, src_len as c_int);
631 let ret = ZSTD_compress(
632 dst.as_mut_ptr() as *mut c_void,
633 dst.len() as size_t,
634 src_ptr as *const c_void,
635 src_len,
636 level as c_int,
637 );
638 if ZSTD_isError(ret) != 0 {
639 return Err(Error::ZSTD(ret));
640 }
641 println!("{:?}", dst.as_slice());
642 Ok(CompressedFrame {
643 src_size: src_len,
644 dst_size: ret,
645 checksum,
646 dst,
647 })
648 }
649}
650
651impl FrameLog {
652 pub fn new() -> Self {
653 let p = unsafe { ZSTD_seekable_createFrameLog(1) };
654 assert!(!p.is_null());
655 FrameLog { p }
656 }
657
658 pub fn log_frame<D: Dst>(&mut self, frame: &CompressedFrame<D>) -> usize {
659 unsafe {
660 ZSTD_seekable_logFrame(
661 self.p,
662 frame.dst_size as c_uint,
663 frame.src_size as c_uint,
664 frame.checksum,
665 ) as usize
666 }
667 }
668
669 pub fn write_all<W: std::io::Write>(&self, mut w: W) -> Result<(), std::io::Error> {
670 let mut output = [0; 1024];
671 let mut output_ = ZSTD_outBuffer {
672 dst: output.as_mut_ptr() as *mut c_void,
673 size: 1024,
674 pos: 0,
675 };
676 unsafe {
677 while ZSTD_seekable_writeSeekTable(self.p, &mut output_) != 0 {
678 w.write_all(&output[..output_.pos as usize])?;
679 output_.pos = 0;
680 }
681 w.write_all(&output[..output_.pos as usize])?;
682 }
683 Ok(())
684 }
685}
686
687struct Chunk {
688 p: *const u8,
689 len: size_t,
690}
691
692unsafe impl Send for Chunk {}
693
694pub fn parallel_compress<W: std::io::Write, D: Dst + 'static>(
695 src: &[u8],
696 mut output: W,
697 level: usize,
698 jobs: usize,
699) -> Result<(), Error> {
700 use std::sync::mpsc::channel;
701 use threadpool::ThreadPool;
702
703 let chunk_size = 256;
704 let n = src.len() / chunk_size + if src.len() % 256 == 0 { 0 } else { 1 };
705 let pool = ThreadPool::new(jobs);
706
707 let (tx, rx) = channel();
708 for (i, chunk) in src.chunks(chunk_size).enumerate() {
709 let tx = tx.clone();
710 let chunk = Chunk {
711 p: chunk.as_ptr(),
712 len: chunk.len() as size_t,
713 };
714 pool.execute(move || {
715 let frame = compress_frame(chunk.p, chunk.len, level).unwrap();
716 tx.send((i, frame))
717 .expect("channel will be there waiting for the pool");
718 });
719 }
720
721 let frames: Vec<CompressedFrame<D>> = unsafe {
722 let mut frames = Vec::with_capacity(n);
723 frames.set_len(n);
724 for (i, frame) in rx.iter().take(n) {
725 frames[i] = frame
726 }
727 frames
728 };
729 let mut log = FrameLog::new();
730 for frame in frames.iter() {
731 output.write_all(frame.as_slice())?;
732 log.log_frame(frame);
733 }
734 log.write_all(&mut output)?;
735 Ok(())
736}
737
738#[test]
739fn test_par() {
740 let input = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut diam ante, sollicitudin a dolor et, volutpat elementum nulla. Etiam nec efficitur nibh, quis rutrum risus. Maecenas quis lorem malesuada, aliquet mi vel, viverra nunc. Donec et nulla sed velit sagittis varius. Suspendisse vestibulum, neque lobortis ornare vestibulum, orci turpis vulputate nisi, ut sodales neque purus eget magna. Nunc condimentum, diam eu consequat venenatis, est nisl semper lorem, et lobortis velit justo sed nulla. Nunc sit amet tempor nunc, vel posuere ipsum. Cras erat tortor, pulvinar ac pretium eu, auctor ac nibh. Duis iaculis porta magna, eu lobortis elit. Duis vitae massa eros. Nulla non magna accumsan, egestas quam sit amet, laoreet lectus.";
741 let mut output = Vec::new();
742 parallel_compress::<&mut Vec<u8>, [u8; 256]>(input, &mut output, 10, 4).unwrap();
743 let mut decomp = Vec::new();
744 let mut s = { Seekable::init_buf(&output).unwrap() };
745 for frame in 0..s.get_num_frames() {
746 let size = s.get_frame_decompressed_size(frame);
747 let n = decomp.len();
748 decomp.extend(std::iter::repeat(0).take(size));
749 s.decompress_frame(&mut decomp[n..], frame);
750 }
751 println!("{:?}", std::str::from_utf8(&decomp).unwrap());
752
753 assert_eq!(&input[..], &decomp[..])
754}
755
756#[test]
757fn test() {
758 let mut cstream = SeekableCStream::new(10, 256).unwrap();
759 let input = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut diam ante, sollicitudin a dolor et, volutpat elementum nulla. Etiam nec efficitur nibh, quis rutrum risus. Maecenas quis lorem malesuada, aliquet mi vel, viverra nunc. Donec et nulla sed velit sagittis varius. Suspendisse vestibulum, neque lobortis ornare vestibulum, orci turpis vulputate nisi, ut sodales neque purus eget magna. Nunc condimentum, diam eu consequat venenatis, est nisl semper lorem, et lobortis velit justo sed nulla. Nunc sit amet tempor nunc, vel posuere ipsum. Cras erat tortor, pulvinar ac pretium eu, auctor ac nibh. Duis iaculis porta magna, eu lobortis elit. Duis vitae massa eros. Nulla non magna accumsan, egestas quam sit amet, laoreet lectus.";
760 let mut input_pos = 0;
761 let mut output = vec![0; input.len()];
762 let mut output_pos = 0;
763 while input_pos < input.len() {
764 let (a, b) = cstream
765 .compress(&mut output[output_pos..], &input[input_pos..])
766 .unwrap();
767 output_pos += a;
768 input_pos += b;
769 }
770 while let Ok(n) = cstream.end_stream(&mut output[output_pos..]) {
771 if n == 0 {
772 break;
773 }
774 output_pos += n;
775 }
776 output.truncate(output_pos);
777 {
778 use std::io::Write;
779 let mut file = std::fs::File::create("test").unwrap();
780 file.write_all(&output).unwrap();
781 }
782 println!("input len = {:?}, pos = {:?}", input.len(), output_pos);
783
784 let mut decomp = Vec::new();
785 let mut s = { Seekable::init_buf(&output).unwrap() };
786 for frame in 0..s.get_num_frames() {
787 let size = s.get_frame_decompressed_size(frame);
788 println!("{:?} {:?}", size, s.get_frame_decompressed_offset(frame));
789 let n = decomp.len();
790 decomp.extend(std::iter::repeat(0).take(size));
791 s.decompress_frame(&mut decomp[n..], frame);
792 }
793 println!("{:?}", std::str::from_utf8(&decomp).unwrap());
794 assert_eq!(&input[..], &decomp[..])
795}