Skip to content

Reading the disc image in place ​

2026-10-23, tenth session. It ran beside the sessions on track props and on the MMX and 3D-card builds.

The viewer in the browser, reading the image from a local server: ARC.BV4 in 3D

The browser viewer opened with ?image=http://127.0.0.1:5183/POD2_0.CUE&file=ARC.BV4. The status bar reads "283 of 283 files" from the image, with the chunks kept in OPFS. © Ubi Soft; shown from our own viewer.

Why ​

Until now every tool read target/disc/, a folder that GameFrame's discinfo.py extracted from the image. The plan (docs/PLAN.md) asked for two more modules. The first reads CD images directly. The second puts every place the files can come from behind one interface: a folder, an image, or a URL the player gives. A player with only the BIN and CUE can now use the viewer as it is.

A CD image is three layers ​

The CUE sheet says where each track starts in the BIN. POD's sheet lists two tracks: data in Mode 1, and the music as one audio track after a two-second pregap. The BIN stores raw 2,352-byte sectors. In a Mode 1 sector the 2,048 bytes of data sit at offset 16, behind a sync pattern and a header. In a Mode 2 Form 1 sector they sit at 24, behind an extra subheader. On top of the sectors sits the ISO 9660 volume, which starts at sector 16 with a descriptor and leads to the directory tree.

The new crate, disc-image, reads all three. It does so through one small trait, "read these bytes at this offset", so the same parser works on a file, on memory, or on a source that has to fetch first.

Checked against the extraction ​

Measured. On the player's image the crate finds exactly what discinfo.py reports: 173,791 data sectors, 65,953 audio sectors, and 781 files in 51 directories. Six of the files are hidden: the AVI videos. The test then reads all 781 files, 354,753,467 bytes, out of the BIN and compares each with the extracted copy. Every byte matches. pod-viewer --image target/cd/POD2_0.CUE list prints the same 289 DATA lines as the folder.

The test also builds a small image of its own in memory, in every layout: a cooked ISO, raw Mode 1, raw Mode 2, a Joliet tree with long names, a CUE sheet with audio after the data, and one file per track. So the code is tested without any game files, which never go into git.

In the browser: fetch only what is read ​

A web page cannot read a file synchronously, but the parser is synchronous. A chunk cache joins the two. When a read needs bytes the cache does not hold, it fails with a list of the missing chunks. The page fetches those chunks (an HTTP range request, or a slice of a dropped file) and runs the read again. The chunks are 1 MB each and are kept in the browser's private file system (OPFS), or in IndexedDB where OPFS cannot write.

Measured in the browser built into the app, with viewer/serve-image.sh serving the image on 127.0.0.1. The first visit read the 283 non-video files in 152 range requests, in 0.85 seconds. A reload made two requests, the CUE sheet and the BIN's size, and took everything else from OPFS. Dropping the .cue with its .bin onto the page works too:

The same image dropped onto the page: the French text table

POD2_0.CUE and POD2_0.BIN dropped together; ?file=DIC_GAM.BMD opened the French text table as soon as it arrived. © Ubi Soft; shown from our own viewer.

The test also showed an old bug. Each new batch of arriving files reset the open file, so a ?file= link opened its file and closed it at once. The viewer now keeps the open file open while the rest arrive.

archive.org and CORS ​

The image is also on archive.org, and the plan asked whether a page could read it there. It cannot. Measured from a page on 127.0.0.1 with a public-domain item: the download URL redirects to a data node, and neither sends Access-Control-Allow-Origin, so the browser blocks the bytes. The data node does answer range requests, and archive.org's metadata API does allow other origins. Natively nothing stands in the way: pod-viewer --url URL --md5 HEX downloads the image once into target/download/, resumes it if it breaks, and checks the MD5. The viewer holds no URL. Whether to fetch the game at all is the player's decision.

Next ​

  • Read a file only when it is opened, so the browser shows the list before it reads 300 MB.
  • Play the CD audio track from the image, now that its sectors are at hand.
  • Offer disc-image to GameFrame's shared crates, with its synthetic tests.

Prose CC0 1.0, code Apache 2.0. POD: Planet of Death is © Ubi Soft; none of its files are on this site.