Skip to content

Commit

Permalink
Fix xz corrupt stream error (closes #207)
Browse files Browse the repository at this point in the history
  • Loading branch information
WilliamVenner committed Feb 8, 2024
1 parent 9cc9a0e commit 0a644f8
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 19 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "gmpublisher",
"private": true,
"version": "2.10.0",
"version": "2.10.1",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "gmpublisher"
version = "2.10.0"
version = "2.10.1"
description = "gmpublisher"
authors = [ "William Venner <[email protected]>" ]
license = "GPL-3.0"
Expand All @@ -24,7 +24,7 @@ tauri-utils = "1.0.0-beta-rc.1"
turbonone = "0.2.1"
rayon = "1.5.0"
parking_lot = { version = "0.11.1", features = [ "serde", "deadlock_detection" ] }
xz2 = "0.1.6"
xz2 = "0.1.7"
indexmap = "1.6.2"
dunce = "1.0.1"
lazy_static = "1.4.0"
Expand Down
34 changes: 22 additions & 12 deletions src-tauri/src/gma/extract.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{fs::{self, File}, io::{BufWriter, Cursor, Read, SeekFrom}, path::{Path, PathBuf}, sync::{Arc, atomic::{AtomicBool, AtomicUsize, Ordering}}};
use std::{fs::{self, File}, io::{BufWriter, Cursor, Read, SeekFrom}, path::{Path, PathBuf}, sync::{atomic::{AtomicBool, AtomicUsize, Ordering}, Arc}};

use crate::{app_data, transactions::Transaction};

Expand Down Expand Up @@ -105,9 +105,14 @@ impl GMAFile {
main_thread_forbidden!();

let input = File::open(path.as_ref())?;
let mut bytes_total = input.metadata().map(|metadata| metadata.len()).ok();

let lzma_decoder = xz2::stream::Stream::new_lzma_decoder(u64::MAX).map_err(|_| GMAError::LZMA)?;
let bytes_total = input.metadata().map(|metadata| metadata.len()).ok();

let lzma_decoder = xz2::stream::Stream::new_lzma_decoder(u64::MAX).map_err(|err| {
eprintln!("LZMA error: {err:?}");
GMAError::LZMA
})?;

let mut xz_decoder = xz2::read::XzDecoder::new_stream(input, lzma_decoder);

let mut output = if let Some(ref bytes_total) = bytes_total {
Expand All @@ -116,24 +121,24 @@ impl GMAFile {
Vec::new()
};

let result = if let Some(bytes_total) = bytes_total.take() {
let result = if let Some(bytes_total) = bytes_total {
transaction.data((turbonone!(), bytes_total));

let bytes_total_f = bytes_total as f64;

let complete = Arc::new(AtomicBool::new(false));
let complete_ref = complete.clone();

struct StupidlyUnsafeProgressMonitorPtr(*const xz2::read::XzDecoder<File>);
unsafe impl Sync for StupidlyUnsafeProgressMonitorPtr {}
unsafe impl Send for StupidlyUnsafeProgressMonitorPtr {}
struct StupidlyUnsafeProgressMonitorPtr<T: Read>(*mut xz2::read::XzDecoder<T>);
unsafe impl<T: Read> Sync for StupidlyUnsafeProgressMonitorPtr<T> {}
unsafe impl<T: Read> Send for StupidlyUnsafeProgressMonitorPtr<T> {}

let xz_decoder_ptr = StupidlyUnsafeProgressMonitorPtr(&xz_decoder as *const _);
let xz_decoder_ptr = StupidlyUnsafeProgressMonitorPtr(&mut xz_decoder as *mut _);
rayon::spawn(move || {
#[allow(clippy::redundant_locals)]
let xz_decoder_ptr = xz_decoder_ptr;
while !complete_ref.load(Ordering::Acquire) {
let xz_decoder = unsafe { &*xz_decoder_ptr.0 };
let xz_decoder = unsafe { &mut *xz_decoder_ptr.0 };

let bytes_read = xz_decoder.total_in() as f64;
transaction.progress(bytes_read / bytes_total_f);
Expand All @@ -154,14 +159,19 @@ impl GMAFile {
xz_decoder.read_to_end(&mut output)
};

output.shrink_to_fit();

if let Err(err) = result {
if !matches!(err.kind(), std::io::ErrorKind::Other) {
// No idea why, but XZ always errors with "corrupt xz stream" even when the decompression succeeds.
// Maybe a difference in the way Gmod encoded the XZ stream?
// Let's just check if the file has been fully read, then naively continue.
let mut input = xz_decoder.into_inner();
if input.read(&mut [0u8]).ok() != Some(0) {
eprintln!("LZMA error: {err:#?}");
return Err(GMAError::LZMA);
}
}

output.shrink_to_fit();

let decompressed_size = output.len() as u64;

let mut gma = GMAFile::read_header(GMAReader::MemBuffer(Cursor::new(output.into())), path)?;
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
"package": {
"productName": "gmpublisher",
"version": "2.10.0"
"version": "2.10.1"
},
"tauri": {
"bundle": {
Expand Down

0 comments on commit 0a644f8

Please sign in to comment.