// iigs/resource.h - typed-C facade over the IIgs Resource Manager. // // Phase 3.4 REAL implementation: parses .rsrc resource forks via the // stdio surface (fopen/fread/fseek/fclose) and serves resources from a // per-file cache. Read-only. No AddResource, no DetachResource, no // partial-load, no encryption - those are features we do not yet need. // // What you GET today: // - openResourceFile(path, accessByte, fileType) -> refNum (>0) or // 0 on failure (errno-style code lands in *err if provided). // - loadResource(type, id) -> Handle (void **) on success; cached so // repeated calls return the same handle. *handle points at the // resource bytes (already read from the file). // - releaseResource(verb, handle) -> 0 on success. verb 0 just // releases the current load; verb 1 also evicts the cache entry // and frees the data. // - closeResourceFile(refNum) -> 0 on success. Frees all cached // handles owned by that file. // // On-disk format (Apple IIgs Toolbox Reference Vol 3, ch.42): // File offset 0: rResourceMap header (24 bytes, little-endian fields // because the 65816 is LE). Field rmToIndex is the file offset of // the rIndex table; rmIndexUsed is the number of valid entries; the // remaining header fields are bookkeeping/zero at build time. // Body bytes: resource payloads at the offsets recorded in rIndex. // At rmToIndex: array of 20-byte rIndex entries, each: // uint16 rType, uint32 rID, uint32 rOffset, uint16 rAttr, // uint32 rSize, uint32 rHandle (zero on disk). // // HLock semantics: // The handles we return are NOT relocatable - they point straight at // a malloc'd payload buffer. That means HLock/HUnlock are no-ops // here. The void ** indirection is preserved so that real Memory // Manager handles can swap in later without changing callers. #ifndef IIGS_RESOURCE_H #define IIGS_RESOURCE_H #ifdef __cplusplus extern "C" { #endif #include // Status codes returned by the typed wrappers. Mirror the runtime's // existing errno-style convention (negative = error). enum { RES_OK = 0, RES_ERR_BLOCKED = -1, // legacy stub marker - kept for // backwards compat with old probes RES_ERR_NOT_STARTED = -2, // openResourceFile not called yet RES_ERR_NOT_FOUND = -3, // file open / resource lookup failed RES_ERR_TOOLBOX = -4, // map header corrupt / IO failure RES_ERR_NO_MEM = -5, // malloc failed RES_ERR_BAD_HANDLE = -6 // release/close given an unknown ref }; // Resource type codes we expect to bundle. See Apple IIgs Toolbox // Reference Vol 3 chapter 42 for the canonical list. #define RES_TYPE_RICON 0x8005 #define RES_TYPE_RTEXT 0x8014 #define RES_TYPE_RPSTRING 0x8015 #define RES_TYPE_RCSTRING 0x8016 // Build-time tunables. These cap the per-process resource footprint. #ifndef IIGS_RES_MAX_FILES #define IIGS_RES_MAX_FILES 2 #endif #ifndef IIGS_RES_MAX_HANDLES #define IIGS_RES_MAX_HANDLES 16 #endif // Resource ID (32-bit on disk and in the rIndex). typedef uint32_t IigsResIdT; // Resource type code (16-bit; high bit reserved for system/extended // types, low 15 bits for the actual code). typedef uint16_t IigsResTypeT; // 24-byte resource map header at the start of every .rsrc file. typedef struct { uint16_t rmVersion; uint32_t rmToIndex; uint16_t rmFileNum; uint16_t rmID; uint32_t rmIndexSize; uint32_t rmIndexUsed; uint16_t rmFreeListSize; uint16_t rmFreeListUsed; uint16_t rmPad; } ResourceMapHeaderT; // 20-byte rIndex entry. typedef struct { uint16_t rType; uint32_t rID; uint32_t rOffset; uint16_t rAttr; uint32_t rSize; uint32_t rHandle; } ResourceIndexEntryT; // Refnum returned by openResourceFile. Zero means "no file"; valid // refnums start at 1. typedef uint16_t ResourceRefNumT; // One-shot init. Returns RES_OK; safe to call more than once. int resourceProbeInit(void); // Reports whether the Resource Manager is alive. Always 1 after // resourceProbeInit() has run. int resourceRuntimeEnabled(void); // Opens a resource fork at `path`. `accessByte` and `fileType` are // accepted for API parity with the toolbox but ignored on read-only // in-memory backends. Returns refnum (>0) on success, 0 on failure. // If `err` is non-NULL it receives RES_OK or one of RES_ERR_*. ResourceRefNumT openResourceFile(const char *path, uint8_t accessByte, uint16_t fileType, int *err); // Closes a resource fork and frees any handles cached for that file. // Returns RES_OK or RES_ERR_BAD_HANDLE. int closeResourceFile(ResourceRefNumT refNum); // Loads a resource by (type, id). Searches all open resource files // in open order and returns a cached handle if the same (type, id) // was previously loaded from any open file. Returns NULL on failure. // // The returned handle is `void **`; `*handle` is the resource bytes. void **loadResource(IigsResTypeT type, IigsResIdT id, int *err); // Releases a previously-loaded resource. // verb 0: keep the cached payload (cheap; the handle may be reused). // verb 1: evict the cache entry and free the payload. // Returns RES_OK on success. int releaseResource(int verb, void **handle); // Convenience: byte size of the resource pointed to by `handle`. // Returns 0 if `handle` is not in the cache. uint32_t getResourceSize(void **handle); // ---- Legacy stub API kept for backwards compatibility ---- // The pre-Phase-3.4 stub exposed iigsLoadResource / iigsGetResourceSize // for the rsrcProbe markers. Those now dispatch to the real // implementation when at least one resource file is open. They report // RES_ERR_NOT_STARTED when no file is open (instead of the old // RES_ERR_BLOCKED), preserving the "did Phase 3.4 land?" signal. void **iigsLoadResource(IigsResTypeT resType, IigsResIdT resId, int *err); uint32_t iigsGetResourceSize(IigsResTypeT resType, IigsResIdT resId, int *err); #ifdef __cplusplus } #endif #endif // IIGS_RESOURCE_H