As the title, really. I'm reading a SEQ file into memory, and need to know how big it is ahead of time. I know that I can get the size in blocks by parsing the directory, although it's ugly, but the disk system itself knows the size in bytes. How can I get it to tell me what it is?
For a SEQ file, the directory holds the location of the first data block; each data block other than the last holds 254 bytes of data and the location of the next block, while the last block holds up to 254 bytes of data along with a count of how many are part of the file. Although the drive can tell when all of the bytes of a file have been read, there's no way it can determine the number of bytes within a file without examining every sector thereof. It's possible that code which uses the block-read (
B-R) command to read the first two bytes of each block while ignoring the remainder might be faster than code which reads all of the data, but trying to determine a file's length is apt to be a slow operation in any case.
It is a little bit involved but doable.
All but the last sector holds 254 bytes of data (2 being set aside for track/sector links to the next sector in the chain). The last sector has a 0 in the
track link field and a number indicating much of the sector is actually used in the
sector link field.
If you need the exact byte size of the file there is no way around crawling through the track/sector chain to get to the last sector. The first sector you get from the file's directory entry.
However, if you just need the "worst case" in number of sectors (fx to be able to bound a buffer), you can get the number of sectors used directly from the directory entry of the SEQ file, without following the chain. (Assuming the disk file has been closed properly, of course.)
Either way, you will have to read in and process the disk's directory structure. There is no DOS command or ROM routine to get the value directly; the disk system itself does not know the size in bytes.
Reading the directory (Filename "$") like described on page 23 of the manual is the way to go. Every other attempt would be even more 'ugly' If not slower.
Going thru the Directory is rather straight forward (the example can be streamlined) Entries are 32 bytes each with the file name in position 3..18 and total number of blocks in 28/29 (Low/High). Simply loop around reading them until the name matches and then pick the length in blocks.
How much will be wasted by taking the number of blocks times 254?
Lets be serious, for a real world application, knowing the size in bytes, prior to reading it anyway, seams rather useless. After all, any knowledge would be only useful to determinate if it can be loaded at all. Taking the number of block times 254 will always end up with 0..253 bytes above real length length, but -and that's important for memory considerations - never below. 253 Bytes at 64 KiB, that is less than 0.4% Not sure if it's really worth to care about.
What will be the price to be payed when doing so?
Using the simplified formula will end up refusing to load files that are exactly within 253 bytes of available space. So before investing much time in alternative routine, one should ask how many files will fall into this size range? Is there a worthwhile gain beside theoretical 100% fill?
Adding an ability to 'fully' load may still end up with an unusable file - at least if extending isa legal operation :)
What is the price of byte exact size determination?
Essentially doing so means reading all blocks to reach the last and then checking how many bytes are used there - which may or may not work as DOS does not really keep record about how far the last block is used at all.
Is There a Sensible Solution?
Well, the last paragraph already had it: Determination of the last block and it's filling level means reading the whole file, so why not
Deny any file with a size clearly above maximum
Read any below that threshold into memory
Break with an error (and reset any marker made so far) if it's larger than the memory available
Clear maximum is defined as the number of blocks that could store a file made up from the maximum memory available for that file or simply
The best part, this is a constant able to be calculated at compile time, so the whole checking at run time comes down to a 16 bit compare.
Performance wise this will perform
- for loadable file like accessing the directory plus reading the file
- for clearly non loadable files abort right after reading the directory
- for the few files between max-size and (max-size mod 254 + 1) take as long as checking it's length by following the blockchain.
So instead of always spending the time to follow the chain, AND then spending that time again to load, every load is reduced to ... well, load time. Only the (asumable) small number of cases of being "just a little bigger than the memory but less than 254" will spend the whole time parsing the chain (which are exactly the cases were it's needed) before issueing a 'To big to load' error..