1#[cfg(test)]
10mod tests;
11
12use oodle_sys;
13
14include!("constants.rs");
15
16pub enum Compressor {
20 None,
22
23 Kraken,
25
26 Leviathan,
28
29 Mermaid,
31
32 Selkie,
34
35 Hydra,
37}
38
39impl Into<oodle_sys::OodleLZ_Compressor> for Compressor {
40 fn into(self) -> oodle_sys::OodleLZ_Compressor {
41 match self {
42 Compressor::None => oodle_sys::OodleLZ_Compressor_OodleLZ_Compressor_None,
43 Compressor::Kraken => oodle_sys::OodleLZ_Compressor_OodleLZ_Compressor_Kraken,
44 Compressor::Leviathan => oodle_sys::OodleLZ_Compressor_OodleLZ_Compressor_Leviathan,
45 Compressor::Mermaid => oodle_sys::OodleLZ_Compressor_OodleLZ_Compressor_Mermaid,
46 Compressor::Selkie => oodle_sys::OodleLZ_Compressor_OodleLZ_Compressor_Selkie,
47 Compressor::Hydra => oodle_sys::OodleLZ_Compressor_OodleLZ_Compressor_Hydra,
48 }
49 }
50}
51
52pub enum CompressionLevel {
62 None,
64
65 SuperFast,
67
68 VeryFast,
70
71 Fast,
73
74 Normal,
76
77 Optimal1,
79
80 Optimal2,
82
83 Optimal3,
85
86 Optimal4,
88
89 Optimal5,
91
92 HyperFast1,
94
95 HyperFast2,
97
98 HyperFast3,
100
101 HyperFast4,
103
104 Optimal,
106
107 HyperFast,
109
110 Max,
112
113 Min,
115}
116
117impl Into<oodle_sys::OodleLZ_CompressionLevel> for CompressionLevel {
118 #[rustfmt::skip]
119 fn into(self) -> oodle_sys::OodleLZ_CompressionLevel {
120 match self {
121 CompressionLevel::None => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_None,
122 CompressionLevel::SuperFast => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_SuperFast,
123 CompressionLevel::VeryFast => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_VeryFast,
124 CompressionLevel::Fast => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_Fast,
125 CompressionLevel::Normal => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_Normal,
126 CompressionLevel::Optimal1 => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_Optimal1,
127 CompressionLevel::Optimal2 => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_Optimal2,
128 CompressionLevel::Optimal3 => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_Optimal3,
129 CompressionLevel::Optimal4 => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_Optimal4,
130 CompressionLevel::Optimal5 => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_Optimal5,
131 CompressionLevel::HyperFast1 => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_HyperFast1,
132 CompressionLevel::HyperFast2 => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_HyperFast2,
133 CompressionLevel::HyperFast3 => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_HyperFast3,
134 CompressionLevel::HyperFast4 => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_HyperFast4,
135 CompressionLevel::Optimal => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_Optimal,
136 CompressionLevel::HyperFast => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_HyperFast,
137 CompressionLevel::Max => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_Max,
138 CompressionLevel::Min => oodle_sys::OodleLZ_CompressionLevel_OodleLZ_CompressionLevel_Min,
139 }
140 }
141}
142
143impl Default for CompressionLevel {
144 fn default() -> Self {
145 CompressionLevel::Normal
146 }
147}
148
149#[derive(Debug, Clone, Copy, PartialEq, Eq)]
151pub enum Profile {
152 Main,
154
155 Reduced,
157}
158
159impl Into<oodle_sys::OodleLZ_Profile> for Profile {
160 fn into(self) -> oodle_sys::OodleLZ_Profile {
161 match self {
162 Profile::Main => oodle_sys::OodleLZ_Profile_OodleLZ_Profile_Main,
163 Profile::Reduced => oodle_sys::OodleLZ_Profile_OodleLZ_Profile_Reduced,
164 }
165 }
166}
167
168impl From<oodle_sys::OodleLZ_Profile> for Profile {
169 fn from(profile: oodle_sys::OodleLZ_Profile) -> Self {
170 match profile {
171 oodle_sys::OodleLZ_Profile_OodleLZ_Profile_Main => Profile::Main,
172 oodle_sys::OodleLZ_Profile_OodleLZ_Profile_Reduced => Profile::Reduced,
173 _ => panic!("Invalid profile"),
174 }
175 }
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Eq)]
180pub enum Jobify {
181 Default,
183
184 Disable,
186
187 Normal,
189
190 Aggressive,
192}
193
194impl Into<oodle_sys::OodleLZ_Jobify> for Jobify {
195 fn into(self) -> oodle_sys::OodleLZ_Jobify {
196 match self {
197 Jobify::Default => oodle_sys::OodleLZ_Jobify_OodleLZ_Jobify_Default,
198 Jobify::Disable => oodle_sys::OodleLZ_Jobify_OodleLZ_Jobify_Disable,
199 Jobify::Normal => oodle_sys::OodleLZ_Jobify_OodleLZ_Jobify_Normal,
200 Jobify::Aggressive => oodle_sys::OodleLZ_Jobify_OodleLZ_Jobify_Aggressive,
201 }
202 }
203}
204
205impl From<oodle_sys::OodleLZ_Jobify> for Jobify {
206 fn from(jobify: oodle_sys::OodleLZ_Jobify) -> Self {
207 match jobify {
208 oodle_sys::OodleLZ_Jobify_OodleLZ_Jobify_Default => Jobify::Default,
209 oodle_sys::OodleLZ_Jobify_OodleLZ_Jobify_Disable => Jobify::Disable,
210 oodle_sys::OodleLZ_Jobify_OodleLZ_Jobify_Normal => Jobify::Normal,
211 oodle_sys::OodleLZ_Jobify_OodleLZ_Jobify_Aggressive => Jobify::Aggressive,
212 _ => panic!("Invalid jobify"),
213 }
214 }
215}
216
217#[derive(Debug, Clone, Copy, PartialEq, Eq)]
225pub struct CompressOptions {
226 unused: u32,
228
229 min_match_len: i32,
232
233 seek_chunk_reset: bool,
235
236 seek_chunk_len: u32,
239
240 profile: Profile,
242
243 dictionary_size: i32,
247
248 space_speed_tradeoff_bytes: i32,
251
252 unused2: i32,
254
255 send_quantum_crcs: bool,
259
260 max_local_dictionary_size: u32,
265
266 make_long_range_matcher: bool,
269
270 match_table_size_log2: i32,
273
274 jobify: Jobify,
276
277 jobify_user_ptr: *mut std::ffi::c_void,
279
280 far_match_min_len: i32,
282
283 far_match_offset_log2: i32,
285
286 reserved: [u32; 4],
288}
289
290impl CompressOptions {
291 pub fn validate(&mut self) {
292 let options: *mut oodle_sys::OodleLZ_CompressOptions = &mut (*self).into();
293 unsafe { oodle_sys::OodleLZ_CompressOptions_Validate(options) };
294 *self = CompressOptions::from(unsafe { *options });
295 }
296}
297
298impl Into<oodle_sys::OodleLZ_CompressOptions> for CompressOptions {
299 fn into(self) -> oodle_sys::OodleLZ_CompressOptions {
300 oodle_sys::OodleLZ_CompressOptions {
301 unused_was_verbosity: self.unused,
302 minMatchLen: self.min_match_len,
303 seekChunkReset: if self.seek_chunk_reset { 1 } else { 0 },
304 seekChunkLen: self.seek_chunk_len as i32,
305 profile: self.profile.into(),
306 dictionarySize: self.dictionary_size,
307 spaceSpeedTradeoffBytes: self.space_speed_tradeoff_bytes,
308 unused_was_maxHuffmansPerChunk: self.unused2,
309 sendQuantumCRCs: if self.send_quantum_crcs { 1 } else { 0 },
310 maxLocalDictionarySize: self.max_local_dictionary_size as i32,
311 makeLongRangeMatcher: if self.make_long_range_matcher { 1 } else { 0 },
312 matchTableSizeLog2: self.match_table_size_log2,
313 jobify: self.jobify.into(),
314 jobifyUserPtr: self.jobify_user_ptr,
315 farMatchMinLen: self.far_match_min_len,
316 farMatchOffsetLog2: self.far_match_offset_log2,
317 reserved: self.reserved,
318 }
319 }
320}
321
322impl From<oodle_sys::OodleLZ_CompressOptions> for CompressOptions {
323 fn from(options: oodle_sys::OodleLZ_CompressOptions) -> Self {
324 Self {
325 unused: options.unused_was_verbosity,
326 min_match_len: options.minMatchLen,
327 seek_chunk_reset: options.seekChunkReset != 0,
328 seek_chunk_len: options.seekChunkLen as u32,
329 profile: options.profile.into(),
330 dictionary_size: options.dictionarySize,
331 space_speed_tradeoff_bytes: options.spaceSpeedTradeoffBytes,
332 unused2: options.unused_was_maxHuffmansPerChunk,
333 send_quantum_crcs: options.sendQuantumCRCs != 0,
334 max_local_dictionary_size: options.maxLocalDictionarySize as u32,
335 make_long_range_matcher: options.makeLongRangeMatcher != 0,
336 match_table_size_log2: options.matchTableSizeLog2,
337 jobify: options.jobify.into(),
338 jobify_user_ptr: options.jobifyUserPtr,
339 far_match_min_len: options.farMatchMinLen,
340 far_match_offset_log2: options.farMatchOffsetLog2,
341 reserved: options.reserved,
342 }
343 }
344}
345
346impl Default for CompressOptions {
347 fn default() -> Self {
348 let options = unsafe {
349 *oodle_sys::OodleLZ_CompressOptions_GetDefault(
350 Compressor::None.into(),
351 CompressionLevel::None.into(),
352 )
353 };
354
355 options.into()
356 }
357}
358
359pub fn compress(
403 compressor: Compressor,
404 decompressed: &[u8],
405 compressed: &mut [u8],
406 level: CompressionLevel,
407 options: Option<CompressOptions>,
408 dictionary_base: Option<&[u8]>,
409 scratch_memory: Option<&mut [u8]>,
410) -> Result<usize, u32> {
411 let options = match options {
412 Some(x) => &x.into(),
413 None => std::ptr::null() as *const _,
414 };
415
416 let dictionary_base = match dictionary_base {
417 Some(x) => x.as_ptr(),
418 None => std::ptr::null(),
419 };
420
421 let (scratch_memory, scratch_memory_len) = match scratch_memory {
422 Some(x) => (x.as_mut_ptr(), x.len() as isize),
423 None => (std::ptr::null_mut(), 0),
424 };
425
426 let result = unsafe {
427 oodle_sys::OodleLZ_Compress(
428 compressor.into(),
429 decompressed.as_ptr() as *const _,
430 decompressed.len() as isize,
431 compressed.as_mut_ptr() as *mut _,
432 level.into(),
433 options,
434 dictionary_base as *const _,
435 std::ptr::null(), scratch_memory as *mut _,
437 scratch_memory_len,
438 ) as usize
439 };
440
441 if result == FAILED as usize {
442 Err(FAILED)
443 } else {
444 let compressed_data = compressed[..result].to_vec();
447 compressed[..result].copy_from_slice(&compressed_data);
448 Ok(result)
449 }
450}
451
452pub enum CheckCRC {
457 No,
458 Yes,
459}
460
461impl Default for CheckCRC {
462 fn default() -> Self {
463 CheckCRC::No
464 }
465}
466
467impl Into<oodle_sys::OodleLZ_CheckCRC> for CheckCRC {
468 fn into(self) -> oodle_sys::OodleLZ_CheckCRC {
469 match self {
470 CheckCRC::No => oodle_sys::OodleLZ_CheckCRC_OodleLZ_CheckCRC_No,
471 CheckCRC::Yes => oodle_sys::OodleLZ_CheckCRC_OodleLZ_CheckCRC_Yes,
472 }
473 }
474}
475
476pub enum Verbosity {
478 None,
480 Minimal,
481 Some,
482 Lots,
483}
484
485impl Default for Verbosity {
486 fn default() -> Self {
487 Verbosity::None
488 }
489}
490
491impl Into<oodle_sys::OodleLZ_Verbosity> for Verbosity {
492 fn into(self) -> oodle_sys::OodleLZ_Verbosity {
493 match self {
494 Verbosity::None => oodle_sys::OodleLZ_Verbosity_OodleLZ_Verbosity_None,
495 Verbosity::Minimal => oodle_sys::OodleLZ_Verbosity_OodleLZ_Verbosity_Minimal,
496 Verbosity::Some => oodle_sys::OodleLZ_Verbosity_OodleLZ_Verbosity_Some,
497 Verbosity::Lots => oodle_sys::OodleLZ_Verbosity_OodleLZ_Verbosity_Lots,
498 }
499 }
500}
501
502pub enum DecodeThreadPhase {
506 One,
507 Two,
508 All,
509 Unthreaded,
510}
511
512impl Default for DecodeThreadPhase {
513 fn default() -> Self {
514 DecodeThreadPhase::Unthreaded
515 }
516}
517
518impl Into<oodle_sys::OodleLZ_Decode_ThreadPhase> for DecodeThreadPhase {
519 #[rustfmt::skip]
520 fn into(self) -> oodle_sys::OodleLZ_Decode_ThreadPhase {
521 match self {
522 DecodeThreadPhase::One => oodle_sys::OodleLZ_Decode_ThreadPhase_OodleLZ_Decode_ThreadPhase1,
523 DecodeThreadPhase::Two => oodle_sys::OodleLZ_Decode_ThreadPhase_OodleLZ_Decode_ThreadPhase2,
524 DecodeThreadPhase::All => oodle_sys::OodleLZ_Decode_ThreadPhase_OodleLZ_Decode_ThreadPhaseAll,
525 DecodeThreadPhase::Unthreaded => oodle_sys::OodleLZ_Decode_ThreadPhase_OodleLZ_Decode_Unthreaded,
526 }
527 }
528}
529
530pub fn decompress(
568 compressed: &[u8],
569 decompressed: &mut [u8],
570 dictionary_base: Option<&mut [u8]>,
571 check_crc: Option<CheckCRC>,
572 verbosity: Option<Verbosity>,
573 thread_phase: Option<DecodeThreadPhase>,
574) -> Result<usize, u32> {
575 let (dictionary_base, dictionary_base_len) = match dictionary_base {
576 Some(x) => (x.as_mut_ptr(), x.len() as isize),
577 None => (std::ptr::null_mut(), 0),
578 };
579
580 let result = unsafe {
581 oodle_sys::OodleLZ_Decompress(
582 compressed.as_ptr() as *const _,
583 compressed.len() as isize,
584 decompressed.as_mut_ptr() as *mut _,
585 decompressed.len() as isize,
586 oodle_sys::OodleLZ_FuzzSafe_OodleLZ_FuzzSafe_Yes,
587 check_crc.unwrap_or_default().into(),
588 verbosity.unwrap_or_default().into(),
589 dictionary_base as *mut _,
590 dictionary_base_len,
591 None, std::ptr::null_mut(),
593 std::ptr::null_mut(),
594 0,
595 thread_phase.unwrap_or_default().into(),
596 ) as usize
597 };
598
599 if result == FAILED as usize {
600 Err(FAILED)
601 } else {
602 Ok(result)
603 }
604}