Files
Eric Dalloandeca-agent b672c6498f Raise the size table entries of the files inside the mods' packs, whose heaps ran out when the game loaded them
The game loads each member of a pack (Pack/**/*.pack.zs) as a resource of its own, in a heap sized by that member's
own entry in the resource size table. The port raised the entries of the mods' loose files only, so a mod that changed
a file inside a pack and shipped no table for it left the game's entry. A crash when heavy snow started in Hebra was
that: an .ainb member of about 13 KB loaded into a heap sized for the game's smaller copy, 0x48 bytes stayed free after
the file, the frame heap gave null for the 0x68-byte object the resource builds next, and main+0x21794c stored that
object's vtable at address 0.

restbl_overlay now unpacks each pack a mod serves and the game's copy of it with the dictionaries of
Pack/ZsDic.pack.zs, and raises each member's entry as it does a loose file's: by the growth for a member the game's
copy has, by the estimate of its type for one it lacks. It never lowers an entry, a mod's own table included, and the
log names the first members it raised. --probe-mods checks restbl_pack_raise on archives of its own, and docs/mods.md
says that the files inside packs count too.

🤖 Generated with [ECA](https://eca.dev) (nubank-anthropic/opus-5.5 - max)

Co-Authored-By: eca-agent <git@eca.dev>
2026-11-05 10:49:55 -03:00

51 lines
3.3 KiB
C

// The game's resource size table (restbl.c): System/Resource/ResourceSizeTable.Product.<n>.Nin_NX_NVN.rsizetable.zs, a
// zstd-compressed RESTBL. The game sizes the buffer it loads a file into from the file's entry, so a mod file larger
// than the original needs a larger entry, and a file a mod adds needs one of its own. romfs.c merges the tables the
// mods ship and raises the entries of the files they serve (romfs.c restbl_overlay).
#pragma once
#include <stddef.h>
#include <stdint.h>
typedef struct Restbl Restbl;
// The table of a decompressed RESTBL (copied); NULL when it is not one.
Restbl *restbl_parse(const uint8_t *data, size_t n);
void restbl_free(Restbl *t);
// The table's key of a RomFS path: the path without a trailing .zs or .mc, into buf.
const char *restbl_key(const char *path, char *buf, size_t n);
// 1 with *size when key has an entry.
int restbl_get(const Restbl *t, const char *key, uint32_t *size);
// The entry of key raised to size (added when missing); 1 when the table changed.
int restbl_raise(Restbl *t, const char *key, uint32_t size);
// Every entry of shipped larger than base's (or missing from base) raised in t; the number of entries raised.
int restbl_merge(Restbl *t, const Restbl *base, const Restbl *shipped);
// Each entry of from whose key one of keys[0..n) names, raised in t; the number raised.
int restbl_take(Restbl *t, const Restbl *from, const char *const *keys, size_t n);
// The table as a decompressed RESTBL (malloc'd); NULL when out of memory.
uint8_t *restbl_write(const Restbl *t, size_t *n);
// The entry a file of the key's type and decompressed size needs when the game has none for it; 0 for a type the
// table never lists (streamed sound and video).
uint32_t restbl_estimate(const char *key, uint64_t size);
// The entry of a file the game lists with `entry` for its own copy of old bytes, now new bytes: raised by the growth
// times the type's factor, never lowered. scaled: the sizes are compressed ones (a mesh codec .mc file), whose entry
// grows in proportion.
uint32_t restbl_grow(const char *key, uint32_t entry, uint64_t old, uint64_t new_size, int scaled);
// The members of the SARC archive p[0..n): each(name, data, size, ctx) for every named member, in the archive's order.
// 0 when p is not a SARC archive or a member lies outside it.
typedef void RestblMember(const char *name, const uint8_t *data, size_t size, void *ctx);
int restbl_sarc_each(const uint8_t *p, size_t n, RestblMember *each, void *ctx);
// A pack (Pack/**/*.pack.zs, decompressed: a SARC archive) whose members the game loads as resources of their own, each
// sized by its own entry. The entries of a mod's pack `mod` raised in t against the game's table `base` and the game's
// copy of the pack `orig` (NULL for a pack the game lacks): a member that grew by restbl_grow, a member the game's copy
// lacks by restbl_estimate, the others left as they are. note(key, entry before, entry after, ctx) for each raised
// entry. The number raised; -1 when either pack is not a SARC archive.
typedef void RestblNote(const char *key, uint32_t was, uint32_t now, void *ctx);
int restbl_pack_raise(Restbl *t, const Restbl *base, const uint8_t *mod, size_t mod_n, const uint8_t *orig,
size_t orig_n, RestblNote *note, void *ctx);
// restbl_probe.c, part of --probe-mods: the number of failed checks.
int restbl_probe(void);