libMeatloaf/lib/meatloaf/cbm_media.h
2024-01-24 13:43:53 -05:00

222 lines
5.9 KiB
C++

#ifndef MEATLOAF_CBM_MEDIA
#define MEATLOAF_CBM_MEDIA
#include "meat_io.h"
#include <map>
#include <bitset>
#include <unordered_map>
#include <sstream>
#include "../../include/debug.h"
#include "string_utils.h"
/********************************************************
* Streams
********************************************************/
class CBMImageStream: public MStream {
public:
CBMImageStream(std::shared_ptr<MStream> is) {
containerStream = is;
_is_open = true;
has_subdirs = false;
}
// MStream methods
bool open() override;
void close() override;
~CBMImageStream() {
//Debug_printv("close");
close();
}
// MStream methods
bool isBrowsable() override { return false; };
bool isRandomAccess() override { return true; };
// read = (size) => this.containerStream.read(size);
virtual uint8_t read() {
uint8_t b = 0;
containerStream->read( &b, 1 );
return b;
}
// readUntil = (delimiter = 0x00) => this.containerStream.readUntil(delimiter);
virtual std::string readUntil( uint8_t delimiter = 0x00 )
{
uint8_t b = 0, r = 0;
std::string bytes = "";
do
{
r = containerStream->read( &b, 1 );
if ( b != delimiter )
bytes += b;
else
break;
} while ( r );
return bytes;
}
// readString = (size) => this.containerStream.readString(size);
virtual std::string readString( uint8_t size )
{
uint8_t b[size];
if ( containerStream->read( b, size ) )
return std::string((char *)b);
return std::string();
}
// readStringUntil = (delimiter = 0x00) => this.containerStream.readStringUntil(delimiter);
virtual std::string readStringUntil( uint8_t delimiter = '\0' )
{
uint8_t b[1];
std::stringstream ss;
while( containerStream->read( b, 1 ) )
{
if ( b[0] == delimiter )
ss << b;
}
return ss.str();
}
// seek = (offset) => this.containerStream.seek(offset + this.media_header_size);
bool seek(uint32_t offset) override { return containerStream->seek(offset + media_header_size); }
// seekCurrent = (offset) => this.containerStream.seekCurrent(offset);
bool seekCurrent(uint32_t offset) { return containerStream->seek(offset); }
bool seekPath(std::string path) override { return false; };
std::string seekNextEntry() override { return ""; };
virtual uint32_t seekFileSize( uint8_t start_track, uint8_t start_sector );
uint32_t read(uint8_t* buf, uint32_t size) override;
uint32_t write(const uint8_t *buf, uint32_t size) override;
void reset() override {
seekCalled = false;
_position = 0;
_size = block_size;
//m_load_address = {0, 0};
}
bool isOpen() override;
std::string url;
protected:
bool seekCalled = false;
std::shared_ptr<MStream> containerStream;
bool _is_open = false;
CBMImageStream* decodedStream;
bool show_hidden = false;
uint8_t media_header_size = 0x00;
uint16_t entry_index = 0; // Currently selected directory entry
uint16_t entry_count = -1; // Directory list entry count (-1 unknown)
enum open_modes { OPEN_READ, OPEN_WRITE, OPEN_APPEND, OPEN_MODIFY };
std::string file_type_label[12] = { "DEL", "SEQ", "PRG", "USR", "REL", "CBM", "DIR", "SUS", "NAT", "CMD", "CFS", "???" };
virtual void seekHeader() = 0;
virtual bool seekNextImageEntry() = 0;
void resetEntryCounter() {
entry_index = 0;
Debug_printv("entry_index[%d]", entry_index);
}
// Disks
virtual uint16_t blocksFree() { return 0; };
virtual uint8_t speedZone( uint8_t track) { return 0; };
virtual bool seekEntry( std::string filename ) { return false; };
virtual bool seekEntry( uint16_t index ) { return false; };
virtual uint16_t readFile(uint8_t* buf, uint16_t size) = 0;
std::string decodeType(uint8_t file_type, bool show_hidden = false);
private:
// Commodore Media
// FILE
friend class P00File;
// FLOPPY DISK
friend class D64File;
friend class D71File;
friend class D80File;
friend class D81File;
friend class D82File;
// HARD DRIVE
friend class DNPFile;
friend class D90File;
// MEDIA ARCHIVE
friend class D8BFile;
friend class DFIFile;
// CASSETTE TAPE
friend class T64File;
friend class TCRTFile;
// CARTRIDGE
friend class CRTFile;
};
/********************************************************
* Utility implementations
********************************************************/
class ImageBroker {
static std::unordered_map<std::string, CBMImageStream*> repo;
public:
template<class T> static T* obtain(std::string url) {
// obviously you have to supply STREAMFILE.url to this function!
if(repo.find(url)!=repo.end()) {
Debug_printv("STREAM FOUND!");
return (T*)repo.at(url);
}
// create and add stream to broker if not found
Debug_printv("STREAM NOT FOUND!");
auto newFile = MFSOwner::File(url);
T* newStream = (T*)newFile->getSourceStream();
// Are we at the root of the pathInStream?
if ( newFile->pathInStream == "")
{
Debug_printv("DIRECTORY [%s]", url.c_str());
}
else
{
Debug_printv("SINGLE FILE [%s]", url.c_str());
}
repo.insert(std::make_pair(url, newStream));
delete newFile;
return newStream;
}
static CBMImageStream* obtain(std::string url) {
return obtain<CBMImageStream>(url);
}
static void dispose(std::string url) {
if(repo.find(url)!=repo.end()) {
auto toDelete = repo.at(url);
repo.erase(url);
delete toDelete;
}
}
};
#endif // MEATLOAF_CBM_MEDIA