mirror of
https://github.com/idolpx/libMeatloaf.git
synced 2025-12-06 04:38:49 -05:00
111 lines
4.3 KiB
C++
111 lines
4.3 KiB
C++
#ifndef MEATLOAF_WRAPPER_DIRECTORY_STREAM
|
|
#define MEATLOAF_WRAPPER_DIRECTORY_STREAM
|
|
|
|
#include <memory>
|
|
#include <fstream>
|
|
|
|
#include "meat_io.h"
|
|
|
|
class idirbuf : public std::filebuf {
|
|
const size_t BUFFER_SIZE = 256;
|
|
std::shared_ptr<MFile> container;
|
|
char* buffer;
|
|
uint8_t phase = 0; // 0 = headers, 1 = files, 2 = footer
|
|
|
|
public:
|
|
idirbuf() {
|
|
buffer = new char[BUFFER_SIZE];
|
|
};
|
|
|
|
~idirbuf() {
|
|
if(buffer != nullptr)
|
|
delete[] buffer;
|
|
}
|
|
|
|
void open(std::shared_ptr<MFile> c) {
|
|
container = c;
|
|
container->rewindDirectory(); // in case we're in the middle of reading here!
|
|
phase = 0;
|
|
}
|
|
|
|
// something will be READING from this stream, that's why we need to implement underflow
|
|
int underflow() override {
|
|
// it is up to us how we will fill this buffer. We can write it single line at
|
|
// a time, or (if made big enough) with whole directory contents, it really
|
|
// doesn't matter, because when everything from the buffer is read, underflow
|
|
// will get called again
|
|
//
|
|
// I divided it into 3 phases, for header, files and footer, but again - any way is OK
|
|
if(phase == 0) {
|
|
// OK, so you are in headers.
|
|
// First you have to fill this buffer line by line or as whole. Doesn't matter.
|
|
// i.e. like this:
|
|
size_t written = lineToBuffer(69,"some header line");
|
|
// When you're done, call this:
|
|
this->setg(buffer, buffer, buffer + written);
|
|
|
|
// of course filling it at once would be easiest, as you just fill it here and set this:
|
|
//phase = 1;
|
|
// if you fill line by line incremet some count and set phase to 1 when all lines written...
|
|
}
|
|
else if(phase == 1) {
|
|
// So now we're in files list phase, let's try and get a file:
|
|
std::unique_ptr<MFile> entry(container->getNextFileInDir());
|
|
|
|
if (entry != nullptr) {
|
|
// There's still a file in this dir, so... Same principle:
|
|
// we'll put BASIV V2 into buffer variable using this function:
|
|
auto readCount = fileToBasicV2(entry.get());
|
|
// and set required pointers:
|
|
this->setg(buffer, buffer, buffer + readCount);
|
|
// we're putting just this oone file in our buffer and exiting
|
|
// underflow will be called to fill it with next file
|
|
}
|
|
else
|
|
phase = 2; // nope, no more files here. Let's change phase, so we can write footer
|
|
// in the same pass. Otherwise we'll get an EOF!
|
|
}
|
|
|
|
if(phase == 2) {
|
|
// ok, so now the footer, again - write it into the buffer and call:
|
|
size_t written = lineToBuffer(69,"bytes free");
|
|
this->setg(buffer, buffer, buffer + written);
|
|
phase = 3;
|
|
// next time underflow is called, we'll just return eof
|
|
}
|
|
else if(phase == 3) {
|
|
// we've past the footer, let's send eof
|
|
return std::char_traits<char>::eof();
|
|
}
|
|
|
|
return this->gptr() == this->egptr()
|
|
? std::char_traits<char>::eof()
|
|
: std::char_traits<char>::to_int_type(*this->gptr());
|
|
};
|
|
|
|
size_t fileToBasicV2(MFile* file, long flags = 0L) {
|
|
// convert MFile to ASCII line
|
|
// we can use some additional FLAGS, i.e. for various CBM-style long directory format (they contain creation date and other info!)
|
|
return lineToBuffer(69,"directory entry line in ASCII"); // return length of BASIC line written to the buffer
|
|
}
|
|
|
|
size_t lineToBuffer(uint16_t lineNumber, const std::string &lineContents) {
|
|
// 1. convert lineContents to PETSCII or whatever is required to send to the C64
|
|
// 2. fill our buffer with next line pointer, line number and converted lineContents
|
|
// for(i...) buffer[i]=XXXX...
|
|
// 3. return how may bytes you put in the buffer:
|
|
return 69;
|
|
}
|
|
};
|
|
|
|
// void exampleStreamFn(std::shared_ptr<MFile> container) {
|
|
// idirbuf dirbuffer;
|
|
// dirbuffer.open(container);
|
|
// std::istream dirStream(&dirbuffer);
|
|
|
|
// // now you can just read BASIC V2 characters from dirStream
|
|
// }
|
|
|
|
|
|
#endif /* MEATLOAF_WRAPPER_DIRECTORY_STREAM */
|