Перенос наработок в новый репозиторий

This commit is contained in:
Valentin Popov 2023-09-17 02:35:58 +04:00
parent a7fd7ba7e9
commit 4e195ec386
Signed by: Valentin Popov
GPG Key ID: AE3CE523DAAA8401
9 changed files with 425 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

105
Cargo.lock generated Normal file
View File

@ -0,0 +1,105 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "itoa"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "packer"
version = "0.1.0"
dependencies = [
"byteorder",
"serde",
"serde_json",
]
[[package]]
name = "proc-macro2"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "serde"
version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "2.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e02e55d62894af2a08aca894c6577281f76769ba47c94d5756bec8ac6e7373"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unpacker"
version = "0.1.1"
dependencies = [
"byteorder",
"serde",
"serde_json",
]

7
Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[workspace]
members = ["packer", "unpacker"]
[profile.release]
codegen-units = 1
lto = true
strip = true

9
packer/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "packer"
version = "0.1.0"
edition = "2021"
[dependencies]
byteorder = "1.4.3"
serde = { version = "1.0.160", features = ["derive"] }
serde_json = "1.0.96"

0
packer/README.md Normal file
View File

170
packer/src/main.rs Normal file
View File

@ -0,0 +1,170 @@
use std::env;
use std::{
fs::{self, File},
io::{BufReader, Read},
};
use byteorder::{ByteOrder, LittleEndian};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
pub struct ImportListElement {
pub extension: String,
pub index: u32,
pub name: String,
pub unknown0: u32,
pub unknown1: u32,
pub unknown2: u32,
}
#[derive(Debug)]
pub struct ListElement {
pub extension: String,
pub index: u32,
pub name: String,
pub position: u32,
pub size: u32,
pub unknown0: u32,
pub unknown1: u32,
pub unknown2: u32,
}
fn main() {
let args: Vec<String> = env::args().collect();
let input = &args[1];
let output = &args[2];
pack(String::from(input), String::from(output));
}
fn pack(input: String, output: String) {
// Загружаем индекс-файл
let index_file = format!("{}/{}", input, "index.json");
let data = fs::read_to_string(index_file).unwrap();
let list: Vec<ImportListElement> = serde_json::from_str(&data).unwrap();
// Общий буфер хранения файлов
let mut content_buffer: Vec<u8> = Vec::new();
let mut list_buffer: Vec<u8> = Vec::new();
// Общее количество файлов
let total_files: u32 = list.len() as u32;
for (index, item) in list.iter().enumerate() {
// Открываем дескриптор файла
let path = format!("{}/{}", input, item.name);
let file = File::open(path).unwrap();
let metadata = file.metadata().unwrap();
// Считываем файл в буфер
let mut reader = BufReader::new(file);
let mut file_buffer: Vec<u8> = Vec::new();
reader.read_to_end(&mut file_buffer).unwrap();
// Выравнивание буфера
if index != 0 {
while content_buffer.len() % 8 != 0 {
content_buffer.push(0);
}
}
// Получение позиции файла
let position = content_buffer.len() + 16;
// Записываем файл в буфер
content_buffer.extend(file_buffer);
// Формируем элемент
let element = ListElement {
extension: item.extension.to_string(),
index: item.index,
name: item.name.to_string(),
position: position as u32,
size: metadata.len() as u32,
unknown0: item.unknown0,
unknown1: item.unknown1,
unknown2: item.unknown2,
};
// Создаем буфер из элемента
let mut element_buffer: Vec<u8> = Vec::new();
// Пишем тип файла
let mut extension_buffer: [u8; 4] = [0; 4];
let mut file_extension_buffer = element.extension.into_bytes();
file_extension_buffer.resize(4, 0);
extension_buffer.copy_from_slice(&file_extension_buffer);
element_buffer.extend(extension_buffer);
// Пишем неизвестное значение #1
let mut unknown0_buffer: [u8; 4] = [0; 4];
LittleEndian::write_u32(&mut unknown0_buffer, element.unknown0);
element_buffer.extend(unknown0_buffer);
// Пишем неизвестное значение #2
let mut unknown1_buffer: [u8; 4] = [0; 4];
LittleEndian::write_u32(&mut unknown1_buffer, element.unknown1);
element_buffer.extend(unknown1_buffer);
// Пишем размер файла
let mut file_size_buffer: [u8; 4] = [0; 4];
LittleEndian::write_u32(&mut file_size_buffer, element.size);
element_buffer.extend(file_size_buffer);
// Пишем неизвестное значение #3
let mut unknown2_buffer: [u8; 4] = [0; 4];
LittleEndian::write_u32(&mut unknown2_buffer, element.unknown2);
element_buffer.extend(unknown2_buffer);
// Пишем название файла
let mut name_buffer: [u8; 36] = [0; 36];
let mut file_name_buffer = element.name.into_bytes();
file_name_buffer.resize(36, 0);
name_buffer.copy_from_slice(&file_name_buffer);
element_buffer.extend(name_buffer);
// Пишем позицию файла
let mut position_buffer: [u8; 4] = [0; 4];
LittleEndian::write_u32(&mut position_buffer, element.position);
element_buffer.extend(position_buffer);
// Пишем индекс файла
let mut index_buffer: [u8; 4] = [0; 4];
LittleEndian::write_u32(&mut index_buffer, element.index);
element_buffer.extend(index_buffer);
// Добавляем итоговый буфер в буфер элементов списка
list_buffer.extend(element_buffer);
}
let mut header_buffer: Vec<u8> = Vec::new();
// Пишем первый тип файла
let mut header_type_1 = [0; 4];
LittleEndian::write_u32(&mut header_type_1, 1936020046_u32);
header_buffer.extend(header_type_1);
// Пишем второй тип файла
let mut header_type_2 = [0; 4];
LittleEndian::write_u32(&mut header_type_2, 256_u32);
header_buffer.extend(header_type_2);
// Пишем количество файлов
let mut header_total_files = [0; 4];
LittleEndian::write_u32(&mut header_total_files, total_files);
header_buffer.extend(header_total_files);
// Пишем общий размер файла
let mut header_total_size = [0; 4];
let total_size: u32 = ((content_buffer.len() + 16) as u32) + (total_files * 64);
LittleEndian::write_u32(&mut header_total_size, total_size);
header_buffer.extend(header_total_size);
let mut result_buffer: Vec<u8> = Vec::new();
result_buffer.extend(header_buffer);
result_buffer.extend(content_buffer);
result_buffer.extend(list_buffer);
fs::write(output, result_buffer).unwrap();
}

9
unpacker/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "unpacker"
version = "0.1.1"
edition = "2021"
[dependencies]
byteorder = "1.4.3"
serde = { version = "1.0.160", features = ["derive"] }
serde_json = "1.0.96"

0
unpacker/README.md Normal file
View File

124
unpacker/src/main.rs Normal file
View File

@ -0,0 +1,124 @@
use std::env;
use std::fs::File;
use std::io::{BufReader, BufWriter, Read, Seek, SeekFrom, Write};
use byteorder::{ByteOrder, LittleEndian};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
pub struct FileHeader {
pub size: u32,
pub total: u32,
pub type1: u32,
pub type2: u32,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ListElement {
pub extension: String,
pub index: u32,
pub name: String,
#[serde(skip_serializing)]
pub position: u32,
#[serde(skip_serializing)]
pub size: u32,
pub unknown0: u32,
pub unknown1: u32,
pub unknown2: u32,
}
fn main() {
let args: Vec<String> = env::args().collect();
let input = &args[1];
let output = &args[2];
unpack(String::from(input), String::from(output));
}
fn unpack(input: String, output: String) {
let file = File::open(input).unwrap();
let metadata = file.metadata().unwrap();
let mut reader = BufReader::new(file);
let mut list: Vec<ListElement> = Vec::new();
// Считываем заголовок файла
let mut header_buffer = [0u8; 16];
reader.seek(SeekFrom::Start(0)).unwrap();
reader.read_exact(&mut header_buffer).unwrap();
let file_header = FileHeader {
size: LittleEndian::read_u32(&header_buffer[12..16]),
total: LittleEndian::read_u32(&header_buffer[8..12]),
type1: LittleEndian::read_u32(&header_buffer[0..4]),
type2: LittleEndian::read_u32(&header_buffer[4..8]),
};
if file_header.type1 != 1936020046 || file_header.type2 != 256 {
panic!("this isn't NRes file");
}
if metadata.len() != file_header.size as u64 {
panic!("incorrect size")
}
// Считываем список файлов
let list_files_start_position = file_header.size - (file_header.total * 64);
let list_files_size = file_header.total * 64;
let mut list_buffer = vec![0u8; list_files_size as usize];
reader
.seek(SeekFrom::Start(list_files_start_position as u64))
.unwrap();
reader.read_exact(&mut list_buffer).unwrap();
if list_buffer.len() % 64 != 0 {
panic!("invalid files list")
}
for i in 0..(list_buffer.len() / 64) {
let from = i * 64;
let to = (i * 64) + 64;
let chunk: &[u8] = &list_buffer[from..to];
let element_list = ListElement {
extension: String::from_utf8_lossy(&chunk[0..4])
.trim_matches(char::from(0))
.to_string(),
index: LittleEndian::read_u32(&chunk[60..64]),
name: String::from_utf8_lossy(&chunk[20..56])
.trim_matches(char::from(0))
.to_string(),
position: LittleEndian::read_u32(&chunk[56..60]),
size: LittleEndian::read_u32(&chunk[12..16]),
unknown0: LittleEndian::read_u32(&chunk[4..8]),
unknown1: LittleEndian::read_u32(&chunk[8..12]),
unknown2: LittleEndian::read_u32(&chunk[16..20]),
};
list.push(element_list)
}
// Распаковываем файлы в директорию
for element in &list {
let path = format!("{}/{}", output, element.name);
let mut file = File::create(path).unwrap();
let mut file_buffer = vec![0u8; element.size as usize];
reader
.seek(SeekFrom::Start(element.position as u64))
.unwrap();
reader.read_exact(&mut file_buffer).unwrap();
file.write_all(&file_buffer).unwrap();
file_buffer.clear();
}
// Выгрузка списка файлов в JSON
let path = format!("{}/{}", output, "index.json");
let file = File::create(path).unwrap();
let mut writer = BufWriter::new(file);
serde_json::to_writer_pretty(&mut writer, &list).unwrap();
writer.flush().unwrap();
}