OXYGENHUB
◆ main openmsx / src / fdc / DiskFactory.cc
3.2 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "DiskFactory.hh"
2
3
#include "DMKDiskImage.hh"
4
#include "DSKDiskImage.hh"
5
#include "DirAsDSK.hh"
6
#include "DiskPartition.hh"
7
#include "RamDSKDiskImage.hh"
8
#include "XSADiskImage.hh"
9
10
#include "File.hh"
11
#include "FileContext.hh"
12
#include "MSXException.hh"
13
#include "Reactor.hh"
14
15
#include "StringOp.hh"
16
17
#include <memory>
18
19
namespace openmsx {
20
21
DiskFactory::DiskFactory(Reactor& reactor_)
22
	: reactor(reactor_)
23
	, syncDirAsDSKSetting(
24
		reactor.getCommandController(), "DirAsDSKmode",
25
		"type of synchronisation between host directory and dir-as-dsk disk image",
26
		DirAsDSK::SyncMode::FULL, EnumSetting<DirAsDSK::SyncMode>::Map{
27
			{"read_only", DirAsDSK::SyncMode::READONLY},
28
			{"full",      DirAsDSK::SyncMode::FULL}})
29
	, bootSectorSetting(
30
		reactor.getCommandController(), "bootsector",
31
		"boot sector type for dir-as-dsk",
32
		DirAsDSK::BootSectorType::DOS2, EnumSetting<DirAsDSK::BootSectorType>::Map{
33
			{"DOS1", DirAsDSK::BootSectorType::DOS1},
34
			{"DOS2", DirAsDSK::BootSectorType::DOS2}})
35
{
36
}
37
38
std::unique_ptr<Disk> DiskFactory::createDisk(
39
	const std::string& diskImage, DiskChanger& diskChanger)
40
{
41
	if (diskImage == "ramdsk") {
42
		return std::make_unique<RamDSKDiskImage>();
43
	}
44
45
	Filename filename(diskImage, userFileContext());
46
	try {
47
		// First try DirAsDSK
48
		return std::make_unique<DirAsDSK>(
49
			diskChanger,
50
			reactor.getCliComm(),
51
			filename,
52
			syncDirAsDSKSetting.getEnum(),
53
			bootSectorSetting.getEnum());
54
	} catch (MSXException&) {
55
		// DirAsDSK didn't work, no problem
56
	}
57
	try {
58
		auto file = std::make_shared<File>(filename.getResolved(), File::OpenMode::PRE_CACHE);
59
		try {
60
			// first try XSA
61
			return std::make_unique<XSADiskImage>(filename, *file);
62
		} catch (MSXException&) {
63
			// XSA didn't work, still no problem
64
		}
65
		try {
66
			// next try dmk
67
			file->seek(0);
68
			return std::make_unique<DMKDiskImage>(filename, file);
69
		} catch (MSXException& /*e*/) {
70
			// DMK didn't work, still no problem
71
		}
72
		// next try normal DSK
73
		return std::make_unique<DSKDiskImage>(filename, std::move(file));
74
75
	} catch (MSXException& e) {
76
		// File could not be opened or (very rare) something is wrong
77
		// with the DSK image. Try to interpret the filename as
78
		//    <filename>:<partition-number>
79
		// Try this last because the ':' character could be
80
		// part of the filename itself. So only try this if
81
		// the name could not be interpreted as a valid
82
		// filename.
83
		auto pos = diskImage.find_last_of(':');
84
		if (pos == std::string::npos) {
85
			// does not contain ':', throw previous exception
86
			throw;
87
		}
88
		std::shared_ptr<SectorAccessibleDisk> wholeDisk;
89
		try {
90
			Filename filename2(diskImage.substr(0, pos));
91
			wholeDisk = std::make_shared<DSKDiskImage>(filename2);
92
		} catch (MSXException&) {
93
			// If this fails we still prefer to show the
94
			// previous error message, because it's most
95
			// likely more descriptive.
96
			throw e;
97
		}
98
		unsigned num = [&] {
99
			auto n = StringOp::stringToBase<10, unsigned>(std::string_view(diskImage).substr(pos + 1));
100
			if (!n) {
101
				// not a valid partition number, throw previous exception
102
				throw e;
103
			}
104
			return *n;
105
		}();
106
		SectorAccessibleDisk& disk = *wholeDisk;
107
		return std::make_unique<DiskPartition>(disk, num, std::move(wholeDisk));
108
	}
109
}
110
111
} // namespace openmsx