Skip to content

Commit 19c9e96

Browse files
committed
Inital commit
0 parents  commit 19c9e96

File tree

8 files changed

+320
-0
lines changed

8 files changed

+320
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target

Cargo.lock

+160
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[workspace]
2+
3+
members = ["xp3-packer","xp3-unpacker"]

readme.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# xp3-tool
2+
3+
Simple XP3 packing / unpacking tools.
4+
5+
## Usage
6+
### Packer
7+
```
8+
xp3-packer.exe <input_dir> <out_xp3>
9+
```
10+
11+
### Unpacker
12+
```
13+
xp3-unpacker.exe <input_xp3> <out_dir>
14+
```

xp3-packer/Cargo.toml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "xp3-packer"
3+
version = "0.1.0"
4+
authors = ["storycraft <storycraft@pancake.sh>"]
5+
edition = "2018"
6+
license = "MIT"
7+
8+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
9+
10+
[dependencies]
11+
xp3 = "0.2.2"
12+

xp3-packer/src/main.rs

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Created on Wed Dec 16 2020
3+
*
4+
* Copyright (c) storycraft. Licensed under the MIT Licence.
5+
*/
6+
7+
use std::{env, fs::File, io::{self, BufWriter, Read, Seek, Write}, path::PathBuf};
8+
9+
use io::BufReader;
10+
use xp3::{header::XP3HeaderVersion, index::file::{IndexInfoFlag, IndexSegmentFlag}, index_set::XP3IndexCompression, writer::XP3Writer};
11+
12+
fn main() {
13+
let args: Vec<String> = env::args().collect();
14+
15+
if args.len() < 3 {
16+
println!("usage: {} <input_dir> <out_xp3>", args[0]);
17+
return;
18+
}
19+
20+
let out = File::create(&args[2]).expect(&format!("Cannot open {} for read", &args[1]));
21+
22+
let mut writer = XP3Writer::start(
23+
BufWriter::new(out),
24+
XP3HeaderVersion::Current {
25+
minor_version: 1,
26+
index_size_offset: 0
27+
},
28+
XP3IndexCompression::Compressed
29+
).expect("Cannot write out_xp3");
30+
31+
add_all_file(&mut writer, &PathBuf::new().join(&args[1]), &PathBuf::new().join(&args[1])).expect("Cannot add files");
32+
writer.finish().expect("Cannot finish file");
33+
34+
}
35+
36+
fn add_all_file<T: Write + Seek>(writer: &mut XP3Writer<T>, root: &PathBuf, dir_path: &PathBuf) -> io::Result<()> {
37+
let dir = std::fs::read_dir(dir_path)?;
38+
39+
for entry in dir {
40+
let entry = entry?;
41+
42+
let path = entry.path();
43+
let path_str = path.to_string_lossy();
44+
45+
let relative_path = path.strip_prefix(root).unwrap().to_string_lossy().to_string();
46+
47+
if path.is_dir() {
48+
let res = add_all_file(writer, root, &path);
49+
if res.is_err() {
50+
println!("Skipping unreadable directory: {}. Err: {:?}", path_str, res.err());
51+
continue;
52+
}
53+
} else {
54+
let file = File::open(&path);
55+
println!("Packing {} ", relative_path);
56+
57+
if file.is_err() {
58+
println!("Skipping unreadable file: {} Err: {:?}", path_str, file.err());
59+
continue;
60+
}
61+
let file = file.unwrap();
62+
63+
let time = path.metadata().unwrap().modified().unwrap().elapsed().unwrap().as_millis() as u64;
64+
65+
let mut buffer = Vec::new();
66+
let mut reader = BufReader::new(file);
67+
68+
reader.read_to_end(&mut buffer)?;
69+
70+
let mut entry = writer.enter_file(IndexInfoFlag::NotProtected, relative_path.clone().replace("\\", &"/"), Some(time));
71+
entry.write_segment(
72+
IndexSegmentFlag::UnCompressed,
73+
&mut buffer
74+
)?;
75+
entry.finish();
76+
}
77+
}
78+
79+
Ok(())
80+
}

xp3-unpacker/Cargo.toml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "xp3-unpacker"
3+
version = "0.1.0"
4+
authors = ["storycraft <storycraft@storyboard.ml>"]
5+
edition = "2018"
6+
license = "MIT"
7+
8+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
9+
10+
[dependencies]
11+
xp3 = "0.2.2"

xp3-unpacker/src/main.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Created on Thu Dec 17 2020
3+
*
4+
* Copyright (c) storycraft. Licensed under the MIT Licence.
5+
*/
6+
7+
use std::{env, fs::{self, File}, io::{BufReader, BufWriter}, path::Path};
8+
9+
use xp3::reader::XP3Reader;
10+
11+
fn main() {
12+
let args: Vec<String> = env::args().collect();
13+
14+
if args.len() < 3 {
15+
println!("usage: {} <input_xp3> <out_dir>", args[0]);
16+
return;
17+
}
18+
19+
let input_xp3 = File::open(&args[1]).expect(&format!("Cannot open {} for read", &args[1]));
20+
let out_dir = args[2].clone();
21+
let archive = XP3Reader::open_archive(BufReader::new(input_xp3)).expect("Input file is invalid");
22+
23+
for (name, _) in archive.entries() {
24+
println!("Extracting: {}", name);
25+
26+
if name.len() > 128 {
27+
println!("Skipping {} . File name is too long.", name);
28+
continue;
29+
}
30+
31+
let path_str = format!("{}/{}", out_dir, name);
32+
let path = Path::new(&path_str);
33+
fs::create_dir_all(path.parent().unwrap()).unwrap();
34+
35+
archive.unpack(&name.into(), &mut BufWriter::new(File::create(path).unwrap())).unwrap();
36+
}
37+
38+
39+
}

0 commit comments

Comments
 (0)