// rsrcProbe.c - Phase 3.4 real Resource Manager smoke probe. // // Replaces the stub-only probe. Builds a tiny in-memory .rsrc fixture, // registers it with mfsRegister, opens it via openResourceFile, loads // a known rText resource, and verifies the bytes match the expected // payload. This exercises the real parser path top-to-bottom without // needing a ProDOS resource fork. // // Markers (page-1 direct page, per cursorProbe convention): // $70 := 0x99 end-of-main success sentinel // $71 := 0x01 if openResourceFile succeeded (refnum != 0) // $72 := 0x01 if loadResource returned a non-NULL handle whose // bytes match "HELLO" and size is 5 // $73 := 0x01 if loadResource second call returned the SAME handle // (cache hit) and closeResourceFile returned RES_OK // // Build: bash demos/build.sh rsrcProbe // Run: bash scripts/runViaFinder.sh demos/rsrcProbe.omf \ // --check 0x70=0x99 0x71=0x01 0x72=0x01 0x73=0x01 #include #include #include #include "iigs/resource.h" // rResourceMap fixture: header + 5-byte rText payload + one rIndex entry. // // Header (24 bytes, little-endian): // rmVersion = 0x0000 // rmToIndex = 0x0000001D (29) // rmFileNum = 0 // rmID = 0 // rmIndexSize = 0x00000014 (20 bytes = 1 entry) // rmIndexUsed = 0x00000001 // rmFreeListSize = 0 // rmFreeListUsed = 0 // rmPad = 0 // Payload (5 bytes) at offset 24: "HELLO" // rIndex entry (20 bytes) at offset 29: // rType = 0x8014 (rText) // rID = 0x00000001 // rOffset = 0x00000018 (24) // rAttr = 0 // rSize = 0x00000005 // rHandle = 0 static const uint8_t kFixture[49] = { // header 0x00, 0x00, // rmVersion 0x1D, 0x00, 0x00, 0x00, // rmToIndex = 29 0x00, 0x00, // rmFileNum 0x00, 0x00, // rmID 0x14, 0x00, 0x00, 0x00, // rmIndexSize = 20 0x01, 0x00, 0x00, 0x00, // rmIndexUsed = 1 0x00, 0x00, // rmFreeListSize 0x00, 0x00, // rmFreeListUsed 0x00, 0x00, // rmPad // payload at offset 24: "HELLO" 0x48, 0x45, 0x4C, 0x4C, 0x4F, // rIndex entry at offset 29 0x14, 0x80, // rType = 0x8014 0x01, 0x00, 0x00, 0x00, // rID = 1 0x18, 0x00, 0x00, 0x00, // rOffset = 24 0x00, 0x00, // rAttr 0x05, 0x00, 0x00, 0x00, // rSize = 5 0x00, 0x00, 0x00, 0x00 // rHandle }; static const char kFixturePath[] = "rsrc.fixture"; static const char kExpectedText[] = "HELLO"; static const uint32_t kExpectedSize = 5; int main(void) { volatile uint8_t *mark0 = (volatile uint8_t *)0x70; volatile uint8_t *mark1 = (volatile uint8_t *)0x71; volatile uint8_t *mark2 = (volatile uint8_t *)0x72; volatile uint8_t *mark3 = (volatile uint8_t *)0x73; *mark0 = 0x10; *mark1 = 0x00; *mark2 = 0x00; *mark3 = 0x00; // Stage the fixture as a read-only memory-backed file. Cast away // const for the mfsRegister buffer pointer; the resource manager // only ever reads. if (mfsRegister(kFixturePath, (void *)kFixture, sizeof(kFixture), sizeof(kFixture), 0) != 0) { while (1) { } } resourceProbeInit(); int rcOpen = 0; ResourceRefNumT ref = openResourceFile(kFixturePath, 0, 0, &rcOpen); if (ref != 0 && rcOpen == RES_OK) { *mark1 = 0x01; } int rcLoad = 0; void **h = loadResource(RES_TYPE_RTEXT, 1, &rcLoad); if (h && rcLoad == RES_OK) { const uint8_t *bytes = (const uint8_t *)*h; uint32_t sz = getResourceSize(h); int match = (sz == kExpectedSize); if (match) { for (uint32_t i = 0; i < kExpectedSize; i++) { if (bytes[i] != (uint8_t)kExpectedText[i]) { match = 0; break; } } } if (match) { *mark2 = 0x01; } } // Second load - cache hit must return the SAME handle. Then // close the file, which must report RES_OK. int rcLoad2 = 0; void **h2 = loadResource(RES_TYPE_RTEXT, 1, &rcLoad2); int sameHandle = (h2 == h && h2 != 0); int rcClose = closeResourceFile(ref); if (sameHandle && rcClose == RES_OK) { *mark3 = 0x01; } *mark0 = 0x99; while (1) { } return 0; }