mirror of
https://github.com/WerWolv/ImHex-Patterns.git
synced 2026-03-27 23:37:04 -05:00
patterns: Add bcss (BeyondCompare SnapShot) file (#338)
* patterns: add bcss (BeyondCompare SnapShot) file * Add entry to readme * Change table entries in alphabetical order * Support both bcss file and uncompressed content * Remove misleading cases, add warning message * Add test cases to bcss.hexpat * ifdef out ImHex-only functionality --------- Co-authored-by: Nik <werwolv98@gmail.com>
This commit is contained in:
168
patterns/bcss.hexpat
Normal file
168
patterns/bcss.hexpat
Normal file
@@ -0,0 +1,168 @@
|
||||
#pragma author ttimasdf
|
||||
#pragma description BeyondCompare Snapshot (BCSS) file
|
||||
|
||||
#pragma magic [42 43 53 53] @ 0x00
|
||||
|
||||
#pragma array_limit 4294967295
|
||||
#pragma pattern_limit 4294967295
|
||||
|
||||
|
||||
import std.io;
|
||||
import std.mem;
|
||||
import std.array;
|
||||
import std.string;
|
||||
import type.magic;
|
||||
|
||||
#ifdef __IMHEX__
|
||||
import hex.dec;
|
||||
import hex.core;
|
||||
#endif
|
||||
|
||||
|
||||
const u8 max_path_size = 1000;
|
||||
str current_path[max_path_size];
|
||||
u8 current_path_level = 0;
|
||||
|
||||
enum EntryType : u8 {
|
||||
DIRECTORY = 0x01,
|
||||
FILE = 0x02,
|
||||
SYMLINK = 0x03,
|
||||
// NULL = 0x00,
|
||||
DIR_END = 0xFF,
|
||||
};
|
||||
|
||||
struct BCSSEntry {
|
||||
EntryType type;
|
||||
match (type) {
|
||||
(EntryType::DIRECTORY) : {
|
||||
// FileName name;
|
||||
std::string::SizedString<u8> name;
|
||||
if (name.size != 0) {
|
||||
u8 unknown[12];
|
||||
on_dir_enter(name.data); // std::string::to_string(name)
|
||||
} else {
|
||||
// some buggy edge cases
|
||||
u8 unknown[6];
|
||||
std::warning(std::format("invalid empty entry current_lvl={} current_pos=0x{:02x}", current_path_level, $));
|
||||
}
|
||||
}
|
||||
(EntryType::FILE) : {
|
||||
std::string::SizedString<u8> name;
|
||||
if (name.size != 0) {
|
||||
u8 unknown[20];
|
||||
#ifdef __IMHEX__
|
||||
hex::core::add_virtual_file(get_vfs_path(name), this); // std::string::to_string(name)
|
||||
#endif
|
||||
} else {
|
||||
// some buggy edge cases
|
||||
u8 unknown[6];
|
||||
std::warning(std::format("invalid empty entry current_lvl={} current_pos=0x{:02x}", current_path_level, $));
|
||||
}
|
||||
//try {
|
||||
// u8 unknown[20];
|
||||
//} catch {
|
||||
// u8 unknown[0];
|
||||
//}
|
||||
}
|
||||
(EntryType::SYMLINK) : {
|
||||
std::string::SizedString<u8> name;
|
||||
u8 unknown[23];
|
||||
std::string::SizedString<u8> target;
|
||||
#ifdef __IMHEX__
|
||||
hex::core::add_virtual_file(get_vfs_path(name + " [s]"), this); // std::string::to_string(name)
|
||||
#endif
|
||||
}
|
||||
(EntryType::DIR_END) : {
|
||||
on_dir_exit();
|
||||
}
|
||||
// (EntryType::NULL) : {
|
||||
// // some buggy edge cases
|
||||
// u8 unknown[7];
|
||||
// std::warning(std::format("invalid empty entry current_lvl={} current_pos=0x{:02x}", current_path_level, $));
|
||||
// }
|
||||
(_): {
|
||||
std::error(std::format("unknown EntryType idx={} current_pos=0x{:02x}", std::core::array_index(), $));
|
||||
}
|
||||
}
|
||||
}[[format_read("fmt_BCSSEntry")]];
|
||||
|
||||
fn on_dir_enter(str folder_name) {
|
||||
// std::print("on_dir_enter folder={} current_lvl={}", folder_name, current_path_level);
|
||||
if (std::string::length(folder_name) > 0) {
|
||||
current_path[current_path_level] = folder_name;
|
||||
current_path_level += 1;
|
||||
} else {
|
||||
std::warning(std::format("invalid folder name {} current_lvl={} current_pos=0x{:02x}", folder_name, current_path_level, $));
|
||||
}
|
||||
};
|
||||
|
||||
fn on_dir_exit() {
|
||||
if (current_path_level > 0) {
|
||||
current_path_level -= 1;
|
||||
} else if (!std::mem::eof()) {
|
||||
std::warning(std::format("on_dir_exit current_lvl already == 0 current_pos=0x{:02x}", $));
|
||||
}
|
||||
// std::print("on_dir_exit current_lvl={}", current_path_level);
|
||||
};
|
||||
|
||||
fn get_vfs_path(str file_name) {
|
||||
str vfs_path = "";
|
||||
if (current_path_level > 0) {
|
||||
vfs_path = current_path[0];
|
||||
for(u8 i = 1, i < current_path_level, i += 1) {
|
||||
//hash_hex = hash_hex + std::format("{:02X}",bytes[i]);
|
||||
vfs_path = vfs_path + "/" + current_path[i];
|
||||
}
|
||||
return vfs_path + "/" + file_name;
|
||||
} else {
|
||||
return file_name;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
fn fmt_BCSSEntry(BCSSEntry e) {
|
||||
try {
|
||||
match (e.type) {
|
||||
(EntryType::DIRECTORY | EntryType::FILE) : {
|
||||
return std::format("{}: {}", (e.type == EntryType::DIRECTORY ? "Dir" : "File"), e.name.data);
|
||||
}
|
||||
(EntryType::SYMLINK) : {
|
||||
return std::format("Symlink: {} -> {}", e.name.data, e.target.data);
|
||||
}
|
||||
(EntryType::DIR_END) : {
|
||||
return "Directory End";
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
return "[FmtErr]";
|
||||
}
|
||||
};
|
||||
|
||||
struct BCSSFile {
|
||||
if (std::mem::read_unsigned(0, 4) == 0x53534342) {
|
||||
type::Magic<"BCSS"> magic;
|
||||
u8 unknown[14];
|
||||
std::string::SizedString<u16> root_path;
|
||||
|
||||
u8 zlib_content[std::mem::size()-$];
|
||||
|
||||
// manually add zlib header which is essential for hex::dec::zlib_decompress
|
||||
const str zlib_header = "\x78\x9c";
|
||||
std::mem::Section zlib_compressed = std::mem::create_section("zlib_compressed");
|
||||
std::mem::copy_value_to_section(zlib_header, zlib_compressed, 0);
|
||||
std::mem::copy_value_to_section(zlib_content, zlib_compressed, 2);
|
||||
u8 zlib[std::mem::get_section_size(zlib_compressed)] @ 0x00 in zlib_compressed;
|
||||
|
||||
#ifdef __IMHEX__
|
||||
std::mem::Section zlib_decompressed = std::mem::create_section("zlib_decompressed");
|
||||
hex::dec::zlib_decompress(zlib, zlib_decompressed, 15);
|
||||
u8 decompressed_content[std::mem::get_section_size(zlib_decompressed)] @ 0x00 in zlib_decompressed;
|
||||
hex::core::add_virtual_file("bcss_content", decompressed_content);
|
||||
std::warning("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n! BCSS file content is compressed !\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nopen `bcss_content` file from the Virtual Filesystem tab and run this pattern on it.");
|
||||
#endif
|
||||
} else {
|
||||
BCSSEntry entries[while(!std::mem::eof())];
|
||||
}
|
||||
};
|
||||
|
||||
BCSSFile bcss_file @ 0x00;
|
||||
Reference in New Issue
Block a user