Skip to content
This repository was archived by the owner on Jun 22, 2023. It is now read-only.

Commit d81712f

Browse files
committed
Fixed offset errors in filename
1 parent a88859c commit d81712f

File tree

5 files changed

+33
-22
lines changed

5 files changed

+33
-22
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "fo2dat"
3-
version = "0.0.5"
3+
version = "0.0.6"
44
authors = ["Adam Kewley <[email protected]>"]
55

66
[dependencies]

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,8 @@ $ fo2dat -xf master.dat -C fo2
2222

2323
**Note**:
2424
- This utility will decompresses zlib-compressed files when it can; however, typical Fallout 2
25-
DAT2 files contain erroneous compression flags. When `fo2dat` cannot be certain that a file is
26-
compressed, it skips decompression
27-
- Most Fallout2 DAT2 files contain duplicate entries, `fo2dat` skips duplicates as they are
28-
encountered (i.e. first instance of an entry is extracted, 2nd does not overwrite)
25+
DAT2 files seem to flag some files as compressed when they don't appear to be. When `fo2dat`
26+
cannot be certain that a file is compressed, it skips decompression
2927

3028

3129
# DAT Spec
@@ -100,7 +98,7 @@ Source: http://falloutmods.wikia.com/wiki/DAT_file_format
10098
| . |
10199
| . |
102100
| filename |
103-
| (ASCII, len = filename_len) |
101+
| (ASCII, len = filename_len + 4) |
104102
| . ----------------|
105103
| . | is_compressed |
106104
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -118,3 +116,7 @@ Source: http://falloutmods.wikia.com/wiki/DAT_file_format
118116
`offset` and ending at `offset + packed_size`
119117
- `is_compressed` can have a value of either `0x0` (uncompressed) or `0x1`
120118
(compressed)
119+
- Filenames are stored in DOS 8.3 format: 8 characters for the file name,
120+
followed by a period (`.`), followed by a 3 character long extension.
121+
- `filename_len` is the length of a filename WITHOUT the period or extension.
122+
Therefore, the length of the full ASCII for `filename` is `filename_len + 4`

src/lib.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use std::io::Write;
1313
use flate2::read::ZlibDecoder;
1414

1515
const DAT_FILE_FOOTER_BYTES: usize = 8;
16-
const DAT_FILE_MIN_SIZE: usize = DAT_FILE_FOOTER_BYTES;
16+
const DAT_FILE_MIN_SIZE: usize = DAT_FILE_FOOTER_BYTES + DATA_SECTION_TERMINATOR_LEN;
17+
18+
const DATA_SECTION_TERMINATOR_LEN: usize = 1;
1719

1820
const TREE_ENTRY_HEADER_SIZE: usize = 4;
1921
const TREE_ENTRY_FOOTER_SIZE: usize = 13;
@@ -82,7 +84,7 @@ pub fn read_tree_entry(data: &[u8]) -> io::Result<(TreeEntry, usize)> {
8284
return Err(err);
8385
}
8486

85-
let filename = match str::from_utf8(&data[TREE_ENTRY_HEADER_SIZE..filename_len]) {
87+
let filename = match str::from_utf8(&data[TREE_ENTRY_HEADER_SIZE..TREE_ENTRY_HEADER_SIZE+filename_len]) {
8688
Ok(s) => {
8789
let mut filename = PathBuf::new();
8890
for el in s.split(TREE_ENTRY_PATH_SEPARATOR) {
@@ -221,48 +223,53 @@ fn get_data_slice_for_entry<'a>(dat_data: &'a[u8], entry: &TreeEntry) -> io::Res
221223
}
222224

223225
fn extract_entry(dat_data: &[u8], output_dir: &Path, entry: TreeEntry) -> io::Result<()> {
224-
let dat_data = get_data_slice_for_entry(&dat_data, &entry)?;
226+
let entry_data = get_data_slice_for_entry(&dat_data, &entry)?;
225227
let output_path = output_dir.join(&entry.filename);
226228

227229
if let Some(parent) = output_path.parent() {
228230
if !parent.exists() {
229231
std::fs::create_dir_all(parent)?;
230-
println!("{}", parent.to_str().unwrap());
231232
}
232233
}
233234

234235
if output_path.exists() {
235236
eprintln!("{}: already exists: skipping", output_path.to_str().unwrap());
236237
} else {
237-
write_entry(&dat_data, &output_path, &entry)?;
238+
write_entry(&entry_data, &output_path, &entry)?;
238239
}
239240

240241
Ok(())
241242
}
242243

243-
fn write_entry(dat_data: &[u8], output_path: &Path, entry: &TreeEntry) -> io::Result<()> {
244-
let mut output_file = std::fs::File::create(&output_path)?;
245-
println!("{}", output_path.to_str().unwrap());
246-
244+
fn write_entry(entry_data: &[u8], output_path: &Path, entry: &TreeEntry) -> io::Result<()> {
247245
if entry.is_compressed {
248-
write_compressed_entry(&dat_data, output_file, &entry)?;
246+
write_compressed_entry(&entry_data, &output_path, &entry)?;
249247
} else {
250-
output_file.write(dat_data)?;
248+
let mut output_file = std::fs::File::create(&output_path)?;
249+
output_file.write(entry_data)?;
251250
}
252251

253252
Ok(())
254253
}
255254

256-
fn write_compressed_entry(dat_data: &[u8], mut output_file: File, entry: &TreeEntry) -> io::Result<()> {
255+
fn write_compressed_entry(dat_data: &[u8], output_path: &Path, entry: &TreeEntry) -> io::Result<()> {
256+
let mut output_file = std::fs::File::create(&output_path)?;
257+
257258
if dat_data.len() < 2 {
258-
eprintln!("{}: smaller than 2 bytes but marked as 'compressed' skipping decompression", entry.filename.to_str().unwrap());
259+
eprintln!("{}: smaller than 2 bytes but marked as compressed: skipping decompression", output_path.to_str().unwrap());
259260
output_file.write(dat_data)?;
260261
} else if dat_data[0] != 0x78 || dat_data[1] != 0xda {
261-
eprintln!("{}: marked as compressed but no magic number: not decompressing", entry.filename.to_str().unwrap());
262+
eprintln!("{}: marked as compressed but no magic number: skipping decompression", output_path.to_str().unwrap());
262263
output_file.write(dat_data)?;
263264
} else {
264265
let mut zlib_reader = ZlibDecoder::new(dat_data);
265266
std::io::copy(&mut zlib_reader, &mut output_file)?;
267+
268+
let decompressed_len = std::fs::metadata(output_path)?.len() as usize;
269+
if decompressed_len != entry.decompressed_size {
270+
eprintln!("{}: decompressed size ({}) does not match expected decompressed size ({})", output_path.to_str().unwrap(), decompressed_len, entry.decompressed_size);
271+
}
266272
}
273+
267274
Ok(())
268275
}

src/main.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,14 @@ fn main() {
4848
if let Err(e) = fo2dat::list_contents(maybe_file.unwrap()) {
4949
print_and_die(e.description(), 1);
5050
}
51-
} else {
51+
} else if should_list {
5252
let cwd = env::current_dir().unwrap();
5353
let output_path = matches.value_of("directory").unwrap_or(cwd.to_str().unwrap());
5454
if let Err(e) = fo2dat::extract(maybe_file.unwrap(), output_path) {
5555
print_and_die(e.description(), 1);
5656
}
57+
} else {
58+
print_and_die("must specify either either '-t' or '-x'", 1);
5759
}
5860
}
5961

0 commit comments

Comments
 (0)