init (messy)
This commit is contained in:
commit
18bff3cc00
10 changed files with 926 additions and 0 deletions
352
src/rco.zig
Normal file
352
src/rco.zig
Normal file
|
@ -0,0 +1,352 @@
|
|||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
defer _ = gpa.deinit();
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var rco_file = try std.fs.cwd().openFile("vsh/resource/explore_plugin_game.rco", .{});
|
||||
defer rco_file.close();
|
||||
|
||||
var rco = try RcoFile.init(allocator, rco_file);
|
||||
defer rco.deinit();
|
||||
|
||||
try rco_file.seekTo(rco.toc_main_tree_offset.?);
|
||||
const packed_size = try rco_file.reader().readInt(u32, .big);
|
||||
const unpacked_size = try rco_file.reader().readInt(u32, .big);
|
||||
const longest_text_size = try rco_file.reader().readInt(u32, .big);
|
||||
std.debug.print("{d} {d} {d}\n", .{ packed_size, unpacked_size, longest_text_size });
|
||||
|
||||
const packed_buf = try allocator.alloc(u8, packed_size);
|
||||
defer allocator.free(packed_buf);
|
||||
_ = try rco_file.readAll(packed_buf);
|
||||
|
||||
var fb = std.io.fixedBufferStream(packed_buf);
|
||||
var al = std.ArrayList(u8).init(allocator);
|
||||
defer al.deinit();
|
||||
|
||||
try std.compress.zlib.decompress(fb.reader(), al.writer());
|
||||
if (al.items.len != unpacked_size) return error.DecompressedSizeDoesNotMatch;
|
||||
|
||||
var nfb = std.io.fixedBufferStream(al.items);
|
||||
|
||||
while (nfb.pos < try nfb.getEndPos()) {
|
||||
try parseTocEntry(nfb.reader());
|
||||
}
|
||||
|
||||
std.debug.print("{any}\n", .{rco});
|
||||
}
|
||||
|
||||
fn parseTocEntry(reader: anytype) !void {
|
||||
const entry_type: TocEntryType = @enumFromInt(try reader.readInt(u16, .big));
|
||||
try reader.skipBytes(2, .{});
|
||||
const entry_label_offset = try reader.readInt(u32, .big);
|
||||
const attributes_offset = try reader.readInt(u32, .big);
|
||||
const children_offset = try reader.readInt(u32, .big);
|
||||
const children_number = try reader.readInt(u32, .big);
|
||||
const next_sibling_offset = try reader.readInt(u32, .big);
|
||||
const prev_sibling_offset = try reader.readInt(u32, .big);
|
||||
const parent_offset = try reader.readInt(u32, .big);
|
||||
try reader.skipBytes(8, .{});
|
||||
|
||||
_ = .{ entry_label_offset, attributes_offset, children_offset, children_number, next_sibling_offset, prev_sibling_offset, parent_offset };
|
||||
|
||||
std.log.debug("Found TOC Entry: {any}", .{entry_type});
|
||||
|
||||
switch (entry_type) {
|
||||
.MainTree,
|
||||
.ScriptTree,
|
||||
.TextTree,
|
||||
.ImageTree,
|
||||
.ModelTree,
|
||||
.SoundTree,
|
||||
.FontTree,
|
||||
.ObjectTree,
|
||||
.AnimTree,
|
||||
=> {},
|
||||
|
||||
.Text => {
|
||||
const text = try RcoFile.Text.init(reader);
|
||||
std.debug.print("Text: {any}\n", .{text});
|
||||
},
|
||||
|
||||
.Image => {
|
||||
const image = try RcoFile.ImageTree.Image.init(reader);
|
||||
std.debug.print("Image: {any}\n", .{image});
|
||||
},
|
||||
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub const TocEntryType = enum(u16) {
|
||||
MainTree = 0x0101,
|
||||
|
||||
ScriptTree = 0x0200,
|
||||
|
||||
TextTree = 0x0300,
|
||||
Text = 0x0301,
|
||||
|
||||
ImageTree = 0x0400,
|
||||
Image = 0x0401,
|
||||
|
||||
ModelTree = 0x0500,
|
||||
Model = 0x0501,
|
||||
|
||||
SoundTree = 0x0600,
|
||||
Sound = 0x0601,
|
||||
|
||||
FontTree = 0x0700,
|
||||
Font = 0x0701,
|
||||
|
||||
ObjectTree = 0x0800,
|
||||
Page = 0x0801,
|
||||
Plane = 0x0802,
|
||||
Button = 0x0803,
|
||||
XMenu,
|
||||
XMList,
|
||||
Progress,
|
||||
Scroll,
|
||||
MList,
|
||||
MItem,
|
||||
_object_unk1 = 0x080B,
|
||||
XItem,
|
||||
TextObject,
|
||||
ModelObject,
|
||||
Spin,
|
||||
Action,
|
||||
ItemSpin,
|
||||
Group,
|
||||
LList,
|
||||
LItem,
|
||||
Edit,
|
||||
Clock,
|
||||
IList,
|
||||
IItem,
|
||||
Icon,
|
||||
UButton,
|
||||
_object_unk2 = 0x081B,
|
||||
CheckboxGroup,
|
||||
CheckboxItem,
|
||||
Meter,
|
||||
EditBox = 0x081F,
|
||||
|
||||
AnimTree = 0x0900,
|
||||
Anim = 0x0901,
|
||||
MoveTo = 0x0902,
|
||||
Recolour = 0x0903,
|
||||
Rotate = 0x0904,
|
||||
Resize = 0x0905,
|
||||
Fade = 0x0906,
|
||||
Delay = 0x0907,
|
||||
FireEvent = 0x0908,
|
||||
Lock = 0x0909,
|
||||
Unlock = 0x090A,
|
||||
SlideOut = 0x090B,
|
||||
|
||||
_,
|
||||
};
|
||||
|
||||
pub const RcoFile = struct {
|
||||
allocator: Allocator,
|
||||
file: std.fs.File,
|
||||
|
||||
compression: Compression,
|
||||
|
||||
toc_main_tree_offset: ?u32,
|
||||
toc_script_tree_offset: ?u32,
|
||||
toc_text_tree_offset: ?u32,
|
||||
toc_sound_tree_offset: ?u32,
|
||||
toc_model_tree_offset: ?u32,
|
||||
toc_image_tree_offset: ?u32,
|
||||
toc_font_tree_offset: ?u32,
|
||||
toc_object_tree_offset: ?u32,
|
||||
toc_anim_tree_offset: ?u32,
|
||||
|
||||
pub fn parse(self: *RcoFile) !void {
|
||||
const rco_header = try self.file.reader().readStructEndian(RcoHeader, .big);
|
||||
self.compression = @enumFromInt(rco_header.prf_compress);
|
||||
self.toc_main_tree_offset = parseOffset(rco_header.toc_main_tree_offset);
|
||||
self.toc_script_tree_offset = parseOffset(rco_header.toc_script_tree_offset);
|
||||
self.toc_text_tree_offset = parseOffset(rco_header.toc_text_tree_offset);
|
||||
self.toc_sound_tree_offset = parseOffset(rco_header.toc_sound_tree_offset);
|
||||
self.toc_model_tree_offset = parseOffset(rco_header.toc_model_tree_offset);
|
||||
self.toc_image_tree_offset = parseOffset(rco_header.toc_image_tree_offset);
|
||||
self.toc_font_tree_offset = parseOffset(rco_header.toc_font_tree_offset);
|
||||
self.toc_object_tree_offset = parseOffset(rco_header.toc_object_tree_offset);
|
||||
self.toc_anim_tree_offset = parseOffset(rco_header.toc_anim_tree_offset);
|
||||
}
|
||||
|
||||
pub fn init(allocator: Allocator, file: std.fs.File) !RcoFile {
|
||||
var self: RcoFile = undefined;
|
||||
self.allocator = allocator;
|
||||
self.file = file;
|
||||
try self.parse();
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn deinit(_: *RcoFile) void {}
|
||||
|
||||
fn parseOffset(offset: u32) ?u32 {
|
||||
return if (offset == std.math.maxInt(u32)) null else offset;
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
self: RcoFile,
|
||||
comptime _: []const u8,
|
||||
_: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
try writer.writeAll("RcoFile{\n");
|
||||
try writer.print(" .compression = {any},\n", .{self.compression});
|
||||
try self.fmtField("toc_main_tree_offset", writer);
|
||||
try self.fmtField("toc_script_tree_offset", writer);
|
||||
try self.fmtField("toc_text_tree_offset", writer);
|
||||
try self.fmtField("toc_sound_tree_offset", writer);
|
||||
try self.fmtField("toc_model_tree_offset", writer);
|
||||
try self.fmtField("toc_image_tree_offset", writer);
|
||||
try self.fmtField("toc_font_tree_offset", writer);
|
||||
try self.fmtField("toc_object_tree_offset", writer);
|
||||
try self.fmtField("toc_anim_tree_offset", writer);
|
||||
try writer.writeAll("}");
|
||||
}
|
||||
|
||||
inline fn fmtField(self: RcoFile, comptime field_name: []const u8, writer: anytype) !void {
|
||||
const field = @field(self, field_name);
|
||||
const format_string = std.fmt.comptimePrint(" .{s} = {{s}}{{?X}},\n", .{field_name});
|
||||
try writer.print(format_string, .{
|
||||
if (field != null) "0x" else "",
|
||||
field,
|
||||
});
|
||||
}
|
||||
|
||||
pub const Compression = enum(u32) {
|
||||
none = 0,
|
||||
zlib = 0x10,
|
||||
rlz = 0x20,
|
||||
};
|
||||
|
||||
pub const Text = struct {
|
||||
language: Language,
|
||||
encoding: Encoding,
|
||||
number_of: u32,
|
||||
|
||||
pub const Language = enum(u16) {
|
||||
Japanese = 0,
|
||||
English_US = 1,
|
||||
French = 2,
|
||||
Spanish_Spain = 3,
|
||||
German = 4,
|
||||
Italian = 5,
|
||||
Dutch = 6,
|
||||
Portuguese_Portugal = 7,
|
||||
Russian = 8,
|
||||
Korean = 9,
|
||||
Chinese_Traditional = 10,
|
||||
Chinese_Simplified = 11,
|
||||
Finnish = 12,
|
||||
Swedish = 13,
|
||||
Danish = 14,
|
||||
Norwegian = 15,
|
||||
Polish = 16,
|
||||
Portuguese_Brazil = 17,
|
||||
English_UK = 18,
|
||||
Turkish = 19,
|
||||
};
|
||||
|
||||
pub const Encoding = enum(u16) {
|
||||
utf8 = 0,
|
||||
utf16 = 1,
|
||||
utf32 = 2,
|
||||
};
|
||||
|
||||
pub const String = extern struct {
|
||||
label_offset: u32,
|
||||
string_length: u32,
|
||||
string_offset: u32,
|
||||
};
|
||||
};
|
||||
|
||||
pub const ImageTree = struct {
|
||||
pub const Image = struct {
|
||||
format: Format,
|
||||
compression: Image.Compression,
|
||||
size: u32,
|
||||
offset: u32,
|
||||
uncompressed_size: ?u32,
|
||||
|
||||
pub fn init(reader: anytype) !Image {
|
||||
var self: Image = undefined;
|
||||
self.format = @enumFromInt(try reader.readInt(u16, .big));
|
||||
self.compression = @enumFromInt(try reader.readInt(u16, .big));
|
||||
self.size = try reader.readInt(u32, .big);
|
||||
self.offset = try reader.readInt(u32, .big);
|
||||
try reader.skipBytes(4, .{});
|
||||
self.uncompressed_size = if (self.compression == .none) null else try reader.readInt(u32, .big);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub const Format = enum(u16) {
|
||||
png = 0,
|
||||
jpeg = 1,
|
||||
tiff = 2,
|
||||
gif = 3,
|
||||
bmp = 4,
|
||||
gim = 5,
|
||||
};
|
||||
|
||||
pub const Compression = enum(u16) {
|
||||
none = 0,
|
||||
zlib = 1,
|
||||
rlz = 2,
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pub const RcoHeader = extern struct {
|
||||
prf_signature: [4]u8,
|
||||
prf_version: [4]u8,
|
||||
prf_unk: u32 = 0,
|
||||
prf_compress: u32,
|
||||
|
||||
toc_main_tree_offset: u32,
|
||||
toc_script_tree_offset: u32,
|
||||
toc_text_tree_offset: u32,
|
||||
toc_sound_tree_offset: u32,
|
||||
toc_model_tree_offset: u32,
|
||||
toc_image_tree_offset: u32,
|
||||
toc_unk: u32 = std.math.maxInt(u32),
|
||||
toc_font_tree_offset: u32,
|
||||
toc_object_tree_offset: u32,
|
||||
toc_anim_tree_offset: u32,
|
||||
|
||||
str_text_table_offset: u32,
|
||||
str_text_table_length: u32,
|
||||
str_text_label_offset: u32,
|
||||
str_text_label_length: u32,
|
||||
str_text_event_offset: u32,
|
||||
str_text_event_length: u32,
|
||||
|
||||
ptr_text_table_offset: u32,
|
||||
ptr_text_table_length: u32,
|
||||
ptr_image_table_offset: u32,
|
||||
ptr_image_table_length: u32,
|
||||
ptr_model_table_offset: u32,
|
||||
ptr_model_table_length: u32,
|
||||
ptr_sound_table_offset: u32,
|
||||
ptr_sound_table_length: u32,
|
||||
ptr_object_table_offset: u32,
|
||||
ptr_object_table_length: u32,
|
||||
ptr_anim_table_offset: u32,
|
||||
ptr_anim_table_length: u32,
|
||||
|
||||
dat_image_table_offset: u32,
|
||||
dat_image_table_length: u32,
|
||||
dat_sound_table_offset: u32,
|
||||
dat_sound_table_length: u32,
|
||||
dat_model_table_offset: u32,
|
||||
dat_model_table_length: u32,
|
||||
dat_unk: [3]u32 = [_]u32{std.math.maxInt(u32)} ** 3,
|
||||
};
|
||||
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
Loading…
Add table
Add a link
Reference in a new issue