Storage
#include "libtini/storage.h"
This header reads and writes full ProDOS files in near memory, and loads entries of resource packs into banked memory. The calls use the standard ProDOS MLI at $BF00. They use no private SmartPort service.
| Function | Purpose |
|---|---|
ti_file_read | Read a full file into a near buffer |
ti_file_write | Create or replace a file from a near buffer |
ti_file_last_error | Get the ProDOS error of the last failure |
ti_pack_load | Load one entry of a TPK1 pack into a new resource |
How file calls operate
- Each call is a synchronous foreground call for one file. It opens, transfers and closes the file before it returns.
- A call that starts while a different call runs returns
TI_E_BUSYbefore it opens a file. - Names are relative to the current ProDOS prefix. A name has 1-15 characters: a capital letter first, then capitals, digits or periods. Paths, lower-case letters and underscores give
TI_E_ARGUMENT. - ProDOS needs a 1 KiB I/O buffer at a page boundary. The shared layouts keep MAIN $B000-$B3FF for it, with the linker symbol
_ti_file_buffer. Do not use these bytes. A layout without this symbol gives that memory to the game, and then no file call can link. See Memory and layouts. - The audio driver pauses while ProDOS controls the machine. Music mutes, and effects and speech stop. The clock stops, thus the pause is not game time.
Standard ProDOS can keep its /RAM disk in the AUX bank 0 bytes that also hold the SHR picture. Thus during a video session, each call does these steps:
- It saves the picture in a temporary resource and sets SHR off.
- It puts the bytes of the OS back and calls ProDOS.
- It saves the changes that ProDOS made.
- It restores the picture and sets SHR on.
This needs a free slot and 32,768 resource bytes. Without them, the call returns TI_E_NOMEM before any ProDOS call. Outside a video session, the call needs no resource, and file calls operate without ti_init.
Only TI_OK means that the transaction is complete. After an error, do not use the data that the call returned. A failed write can leave a changed or partial file. Keep two save slots and check them, as Saved games shows.
Functions
ti_file_read
ti_error ti_file_read(const char *name, void *dst, uint16_t capacity, uint16_t *length);
This function reads the full file into dst and stores its size in *length. When the file is larger than capacity, the function reads nothing. For an empty file, the buffer can be NULL with a zero capacity.
Returns
TI_OK | The full file is in dst. |
TI_E_ARGUMENT | length is not writable near memory, or the name is not valid. |
TI_E_RANGE | dst is not writable near memory for capacity bytes, or the file is larger than capacity. |
TI_E_BUSY | A different storage call runs. |
TI_E_NOMEM | During a video session, no space is available for the screen loan. |
TI_E_IO | ProDOS did not open, size, read or close the file. See ti_file_last_error. |
*length is 0 when the call does not succeed.
ti_file_write
ti_error ti_file_write(const char *name, const void *src, uint16_t length);
When the file does not exist, this function creates it as a binary file (ProDOS type $06). It writes length bytes and sets the end of file to exactly length. Then it closes the file, which writes the data and the directory to the disk. When the old file was longer, the function makes it shorter. A zero length gives an empty file.
Returns
TI_OK; TI_E_RANGE when src is not readable near memory for length bytes; TI_E_ARGUMENT for a name that is not valid; TI_E_BUSY; TI_E_NOMEM as above; TI_E_IO when a ProDOS create, open, write, set-EOF or close fails.
ti_file_last_error
uint8_t ti_file_last_error(void);
This function returns the ProDOS MLI error code of the last failed call. After a successful call, it returns 0. A read or write that is shorter than expected records $4C. Argument, range and memory errors do not record a new ProDOS code. Read this value together with the result of the call.
| Code | ProDOS meaning |
|---|---|
| $27 | I/O error |
| $2B | Disk write-protected |
| $40 | Invalid pathname |
| $44 | Path not found |
| $45 | Volume not found |
| $46 | File not found |
| $48 | Volume full |
| $49 | Volume directory full |
| $4C | End of file encountered |
| $4E | Access error, for example a locked file |
ti_pack_load
ti_error ti_pack_load(const char *name, const char *entry,
ti_handle *out, uint32_t *size);
This function opens the TPK1 pack name and checks its full directory. It allocates one resource of the size of the entry. Then it moves the bytes of the entry into the resource in pieces of 128 bytes. After a success, the caller owns the handle and frees it with ti_res_free. After an error, the function closes the file, frees a partly loaded resource and sets the two outputs to zero.
An entry name has 1-15 characters: a capital letter, then capitals, digits, periods or underscores. File names keep the narrower ProDOS rule. The function does not interpret the entry. Read its TI4, TIF or TIM header and make the surface, font or map view yourself, as Art, fonts, maps and packs shows. A pack needs an active ti_init grant.
Returns
TI_OK | *out owns a resource of *size bytes. |
TI_E_ARGUMENT | An output is not writable, or the file or entry name is not valid. |
TI_E_UNAVAILABLE | The pack does not have this entry. |
TI_E_FORMAT | The directory is not correct: header, count, names, order, offsets or sizes. The function also checks the entries that it does not load. |
TI_E_NOMEM, TI_E_STATE | No slot or space is available for the entry or the screen loan, or there is no ti_init. |
TI_E_IO | A ProDOS open, read, seek or close failed. |
TI_E_BUSY | A different storage call runs. |
ti_handle art;
uint32_t bytes;
if (ti_pack_load("RESOURCES.TPK", "SHIP", &art, &bytes) != TI_OK) return;
/* ... make views of art; ti_res_free(art) when done ... */
Data formats gives the pack format. tools/assets.py pack writes packs. The disk packager of the repository stores files of a maximum of 131,072 bytes. Use a different ProDOS tool for larger packs. The loader can read them.