37 bool doubleSidedDrive_,
38 std::function<
void()> preChangeCallback_)
39 : reactor(board.getReactor())
40 , controller(board.getCommandController())
41 , stateChangeDistributor(&board.getStateChangeDistributor())
42 , scheduler(&board.getScheduler())
43 , preChangeCallback(std::move(preChangeCallback_))
44 , driveName(std::move(driveName_))
45 , doubleSidedDrive(doubleSidedDrive_)
52 , controller(reactor.getCommandController())
53 , stateChangeDistributor(nullptr)
55 , driveName(std::move(driveName_))
56 , doubleSidedDrive(true)
61 void DiskChanger::init(std::string_view prefix,
bool createCmd)
67 if (stateChangeDistributor) {
74 if (diskCommand)
return;
75 diskCommand.emplace(controller, *
this);
80 if (stateChangeDistributor) {
89 return disk->getName();
94 bool ret = diskChangedFlag || disk->hasChanged();
95 diskChangedFlag =
false;
101 if (
dynamic_cast<DummyDisk*
>(disk.get())) {
112 void DiskChanger::sendChangeDiskEvent(std::span<const TclObject> args)
115 if (stateChangeDistributor) {
123 void DiskChanger::signalStateChange(
const StateChange& event)
125 const auto* commandEvent =
dynamic_cast<const MSXCommandEvent*
>(&event);
126 if (!commandEvent)
return;
128 execute(commandEvent->getTokens());
131 void DiskChanger::execute(std::span<const TclObject> tokens)
134 if (tokens[1] ==
"eject") {
142 void DiskChanger::stopReplay(EmuTime::param ) noexcept
162 std::unique_ptr<Disk> newDisk(diskFactory.createDisk(diskImage, *
this));
172 void DiskChanger::ejectDisk()
179 if (preChangeCallback) preChangeCallback();
180 disk = std::move(newDisk);
181 diskChangedFlag =
true;
191 :
Command(commandController_, diskChanger_.driveName)
192 , diskChanger(diskChanger_)
198 if (tokens.size() == 1) {
203 if (
dynamic_cast<DummyDisk*
>(diskChanger.disk.get())) {
205 }
else if (
dynamic_cast<DirAsDSK*
>(diskChanger.disk.get())) {
210 if (diskChanger.disk->isWriteProtected()) {
217 }
else if (tokens[1] ==
"ramdsk") {
221 diskChanger.sendChangeDiskEvent(args);
222 }
else if (tokens[1] ==
"-ramdsk") {
224 diskChanger.sendChangeDiskEvent(args);
225 result =
"Warning: use of '-ramdsk' is deprecated, instead use the 'ramdsk' subcommand";
226 }
else if (tokens[1] ==
"-eject") {
228 diskChanger.sendChangeDiskEvent(args);
229 result =
"Warning: use of '-eject' is deprecated, instead use the 'eject' subcommand";
230 }
else if (tokens[1] ==
"eject") {
232 diskChanger.sendChangeDiskEvent(args);
234 int firstFileToken = 1;
235 if (tokens[1] ==
"insert") {
236 if (tokens.size() > 2) {
244 for (
size_t i = firstFileToken; i < tokens.size(); ++i) {
245 std::string_view option = tokens[i].
getString();
246 if (option ==
"-ips") {
247 if (++i == tokens.size()) {
249 "Missing argument for option \"", option,
'\"');
251 args.emplace_back(tokens[i]);
254 args.emplace_back(option);
257 diskChanger.sendChangeDiskEvent(args);
268 driveName,
" eject : remove disk from virtual drive\n",
269 driveName,
" ramdsk : create a virtual disk in RAM\n",
270 driveName,
" insert <filename> : change the disk file\n",
271 driveName,
" <filename> : change the disk file\n",
272 driveName,
" : show which disk image is in drive\n"
273 "The following options are supported when inserting a disk image:\n"
274 "-ips <filename> : apply the given IPS patch to the disk image");
279 if (tokens.size() >= 2) {
280 using namespace std::literals;
281 static constexpr std::array extra = {
282 "eject"sv,
"ramdsk"sv,
"insert"sv,
290 return tokens.size() > 1;
300 template<
typename Archive>
303 DiskName diskname = disk->getName();
304 if (ar.versionBelow(version, 2)) {
308 if (
filename.getOriginal() ==
"ramdisk") {
314 ar.serialize(
"disk", diskname);
317 std::vector<Filename> patches;
318 if constexpr (!Archive::IS_LOADER) {
321 ar.serialize(
"patches", patches);
323 auto& filePool = reactor.getFilePool();
325 if constexpr (!Archive::IS_LOADER) {
326 oldChecksum = calcSha1(getSectorAccessibleDisk(), filePool);
328 ar.serialize(
"checksum", oldChecksum);
330 if constexpr (Archive::IS_LOADER) {
341 assert(!oldChecksum.empty());
344 if (file.is_open()) {
348 std::vector<TclObject> args =
350 for (
auto& p : patches) {
351 p.updateAfterLoadState();
352 args.emplace_back(p.getResolved());
359 "Couldn't reinsert disk in drive ",
360 getDriveName(),
": ",
e.getMessage());
366 string newChecksum = calcSha1(getSectorAccessibleDisk(), filePool);
367 if (oldChecksum != newChecksum) {
368 controller.getCliComm().printWarning(
369 "The content of the diskimage ",
371 " has changed since the time this savestate was "
372 "created. This might result in emulation problems "
373 "or even diskcorruption. To prevent the latter, "
374 "the disk is now write-protected (eject and "
375 "reinsert the disk if you want to override this).");
381 ar.serialize(
"diskChanged", diskChangedFlag);
387 using type = std::tuple<std::string>;
389 template<
typename Archive>
395 template<
typename Archive>
type load(Archive& ar,
unsigned )
398 ar.serialize(
"driveName", driveName);
405 std::reference_wrapper<MSXMotherBoard>);
virtual void update(UpdateType type, std::string_view name, std::string_view value)=0
Interpreter & getInterpreter() const final
virtual CliComm & getCliComm()=0
static void completeFileName(std::vector< std::string > &tokens, const FileContext &context, const RANGE &extra)
const DiskName & getDiskName() const
int insertDisk(const std::string &filename) override
const std::string & getDriveName() const
std::string_view getContainerName() const override
void serialize(Archive &ar, unsigned version)
DiskChanger(MSXMotherBoard &board, std::string driveName, bool createCmd=true, bool doubleSidedDrive=true, std::function< void()> preChangeCallback={})
void changeDisk(std::unique_ptr< Disk > newDisk)
SectorAccessibleDisk * getSectorAccessibleDisk() override
bool diskChanged() override
bool needRecord(std::span< const TclObject > tokens) const
std::string help(std::span< const TclObject > tokens) const override
Print help for this command.
void execute(std::span< const TclObject > tokens, TclObject &result) override
Execute this command.
void tabCompletion(std::vector< std::string > &tokens) const override
Attempt tab completion for this command.
DiskCommand(CommandController &commandController, DiskChanger &diskChanger)
void unregisterDrive(DiskContainer &drive)
void registerDrive(DiskContainer &drive, std::string_view prefix)
std::string getResolved() const
void updateAfterLoadState()
File getFile(FileType fileType, const Sha1Sum &sha1sum)
Search file with the given sha1sum.
const std::string & getURL() const
Returns the URL of this file object.
This class represents a filename.
This class is used to for Tcl commands that directly influence the MSX state (e.g.
std::string_view getMachineID() const
Contains the main loop of openMSX.
DiskFactory & getDiskFactory()
DiskManipulator & getDiskManipulator()
EmuTime::param getCurrentTime() const
Get the current scheduler time.
Sha1Sum getSha1Sum(FilePool &filepool)
Calculate SHA1 of the content of this disk.
std::vector< Filename > getPatches() const
This class represents the result of a sha1 calculation (a 160-bit value).
std::string toString() const
void registerListener(StateChangeListener &listener)
(Un)registers the given object to receive state change events.
void distributeNew(EmuTime::param time, Args &&...args)
Deliver the event to all registered listeners MSX input devices should call the distributeNew() versi...
void unregisterListener(StateChangeListener &listener)
unsigned getListLength(Interpreter &interp) const
void addListElement(const T &t)
zstring_view getString() const
bool exists(zstring_view filename)
Does this file (directory) exists?
const std::string & getConventionalPath(const std::string &path)
Returns the path in conventional path-delimiter.
This file implemented 3 utility functions:
constexpr const char *const filename
REGISTER_POLYMORPHIC_CLASS_1(DiskContainer, DiskChanger, "DiskChanger", std::reference_wrapper< MSXMotherBoard >)
FileContext userFileContext(string_view savePath)
constexpr auto drop(Range &&range, size_t n)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
TemporaryString tmpStrCat(Ts &&... ts)
std::string strCat(Ts &&...ts)
void save(Archive &ar, const DiskChanger &changer)
type load(Archive &ar, unsigned)
std::tuple< std::string > type
Serialize (local) constructor arguments.