Now all data is seen by the decoder as a stream that can be read (regardless of its content type) or rewound.
Previously (since only MFM was supported) there was no distinction or abstraction between the data represented by the IPF file, and how it was encoded to represent the “real” (in the case of the library’s, MFM encoded) data as seen through a virtual disk; this was a bit hacky, but very fast. Obviously, with different physical encodings possible per logical block now, this approach is no longer feasible, or would lead to extremely bloated, unmaintainable code, with loads of branching depending on the encoding type used.
A better approach is to reflect how the encoder in the analyser works (which was designed to handle different encodings, although not used yet) using different access layers and reverse the process.
When trying to fill data buffers with disk data, the library would:
- First try to obtain the real disk data needed, as long as a stream of pre-cached/encoded physical data is available, the relevant part of the physical data stream is returned.
- If the physical data under-runs, logical data pre-cached/calculated would be read and encoded.
- If the logical data under-runs the IPF stream gets decoded.
As it can be seen, in the worst case three layers of streams are accessed, but on average this is normally only limited to the physical data layer. While this is significantly more complex than how MFM-only support was implemented, with this architecture the new encoder can be introduced without the need to re-test the entire library and any code path not related to generating the physical encoding itself. Most of the generation of the physical encoding itself (apart from application specific needs) is already delegated to a common code-base shared among all of our applications, and should work correctly as it is part of DTC.