openMSX
FilePool.cc
Go to the documentation of this file.
1#include "FilePool.hh"
2#include "File.hh"
3#include "FileContext.hh"
4#include "FileOperations.hh"
5#include "TclObject.hh"
6#include "CommandException.hh"
7#include "Display.hh"
8#include "EventDistributor.hh"
9#include "CliComm.hh"
10#include "Reactor.hh"
11#include "outer.hh"
12#include "xrange.hh"
13#include <memory>
14
15namespace openmsx {
16
17[[nodiscard]] static TclObject initialFilePoolSettingValue()
18{
19 TclObject result;
20
21 for (const auto& p : systemFileContext().getPaths()) {
22 result.addListElement(
23 makeTclDict("-path", tmpStrCat(p, "/systemroms"),
24 "-types", "system_rom"),
25 makeTclDict("-path", tmpStrCat(p, "/software"),
26 "-types", "rom disk tape"));
27 }
28 return result;
29}
30
32 : core(FileOperations::getUserDataDir() + "/.filecache",
33 [&] { return getDirectories(); },
34 [&](std::string_view message) { reportProgress(message); })
35 , filePoolSetting(
36 controller, "__filepool",
37 "This is an internal setting. Don't change this directly, "
38 "instead use the 'filepool' command.",
39 initialFilePoolSettingValue().getString())
40 , reactor(reactor_)
41 , sha1SumCommand(controller)
42{
43 filePoolSetting.attach(*this);
44 reactor.getEventDistributor().registerEventListener(EventType::QUIT, *this);
45}
46
48{
50 filePoolSetting.detach(*this);
51}
52
53File FilePool::getFile(FileType fileType, const Sha1Sum& sha1sum)
54{
55 return core.getFile(fileType, sha1sum);
56}
57
59{
60 return core.getSha1Sum(file);
61}
62
63[[nodiscard]] static FileType parseTypes(Interpreter& interp, const TclObject& list)
64{
65 auto result = FileType::NONE;
66 for (auto i : xrange(list.getListLength(interp))) {
67 std::string_view elem = list.getListIndex(interp, i).getString();
68 if (elem == "system_rom") {
69 result |= FileType::SYSTEM_ROM;
70 } else if (elem == "rom") {
71 result |= FileType::ROM;
72 } else if (elem == "disk") {
73 result |= FileType::DISK;
74 } else if (elem == "tape") {
75 result |= FileType::TAPE;
76 } else {
77 throw CommandException("Unknown type: ", elem);
78 }
79 }
80 return result;
81}
82
83FilePoolCore::Directories FilePool::getDirectories() const
84{
86 try {
87 auto& interp = filePoolSetting.getInterpreter();
88 const TclObject& all = filePoolSetting.getValue();
89 for (auto i : xrange(all.getListLength(interp))) {
90 FilePoolCore::Dir dir;
91 bool hasPath = false;
92 dir.types = FileType::NONE;
93 TclObject line = all.getListIndex(interp, i);
94 unsigned numItems = line.getListLength(interp);
95 if (numItems & 1) {
96 throw CommandException(
97 "Expected a list with an even number "
98 "of elements, but got ", line.getString());
99 }
100 for (unsigned j = 0; j < numItems; j += 2) {
101 std::string_view name = line.getListIndex(interp, j + 0).getString();
102 TclObject value = line.getListIndex(interp, j + 1);
103 if (name == "-path") {
104 dir.path = value.getString();
105 hasPath = true;
106 } else if (name == "-types") {
107 dir.types = parseTypes(interp, value);
108 } else {
109 throw CommandException("Unknown item: ", name);
110 }
111 }
112 if (!hasPath) {
113 throw CommandException(
114 "Missing -path item: ", line.getString());
115 }
116 if (dir.types == FileType::NONE) {
117 throw CommandException(
118 "Missing -types item: ", line.getString());
119 }
120 result.push_back(std::move(dir));
121 }
122 } catch (CommandException& e) {
123 reactor.getCliComm().printWarning(
124 "Error while parsing '__filepool' setting", e.getMessage());
125 }
126 return result;
127}
128
129void FilePool::update(const Setting& setting) noexcept
130{
131 assert(&setting == &filePoolSetting); (void)setting;
132 (void)getDirectories(); // check for syntax errors
133}
134
135void FilePool::reportProgress(std::string_view message)
136{
137 if (quit) core.abort();
138 reactor.getCliComm().printProgress(message);
139 reactor.getDisplay().repaint();
140}
141
142int FilePool::signalEvent(const Event& event)
143{
144 (void)event; // avoid warning for non-assert compiles
145 assert(getType(event) == EventType::QUIT);
146 quit = true;
147 return 0;
148}
149
150
151// class Sha1SumCommand
152
153FilePool::Sha1SumCommand::Sha1SumCommand(
154 CommandController& commandController_)
155 : Command(commandController_, "sha1sum")
156{
157}
158
159void FilePool::Sha1SumCommand::execute(std::span<const TclObject> tokens, TclObject& result)
160{
161 checkNumArgs(tokens, 2, "filename");
162 File file(FileOperations::expandTilde(std::string(tokens[1].getString())));
163 auto& filePool = OUTER(FilePool, sha1SumCommand);
164 result = filePool.getSha1Sum(file).toString();
165}
166
167std::string FilePool::Sha1SumCommand::help(std::span<const TclObject> /*tokens*/) const
168{
169 return "Calculate sha1 value for the given file. If the file is "
170 "(g)zipped the sha1 is calculated on the unzipped version.";
171}
172
173void FilePool::Sha1SumCommand::tabCompletion(std::vector<std::string>& tokens) const
174{
175 completeFileName(tokens, userFileContext());
176}
177
178} // namespace openmsx
BaseSetting * setting
Definition: Interpreter.cc:28
void printProgress(std::string_view message)
Definition: CliComm.cc:20
void printWarning(std::string_view message)
Definition: CliComm.cc:10
void repaint()
Redraw the display.
Definition: Display.cc:364
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
Sha1Sum getSha1Sum(File &file)
Calculate sha1sum for the given File object.
File getFile(FileType fileType, const Sha1Sum &sha1sum)
Search file with the given sha1sum.
void abort()
This is only meaningful to call from within the 'reportProgress' callback (constructor parameter).
Definition: FilePoolCore.hh:68
std::vector< Dir > Directories
Definition: FilePoolCore.hh:44
FilePool(CommandController &controller, Reactor &reactor)
Definition: FilePool.cc:31
Sha1Sum getSha1Sum(File &file)
Calculate sha1sum for the given File object.
Definition: FilePool.cc:58
File getFile(FileType fileType, const Sha1Sum &sha1sum)
Search file with the given sha1sum.
Definition: FilePool.cc:53
Contains the main loop of openMSX.
Definition: Reactor.hh:68
Display & getDisplay()
Definition: Reactor.hh:86
CliComm & getCliComm()
Definition: Reactor.cc:313
EventDistributor & getEventDistributor()
Definition: Reactor.hh:82
Interpreter & getInterpreter() const
Definition: Setting.cc:148
const TclObject & getValue() const final
Gets the current value of this setting as a TclObject.
Definition: Setting.hh:142
This class represents the result of a sha1 calculation (a 160-bit value).
Definition: sha1.hh:23
void detach(Observer< T > &observer)
Definition: Subject.hh:56
unsigned getListLength(Interpreter &interp) const
Definition: TclObject.cc:134
TclObject getListIndex(Interpreter &interp, unsigned index) const
Definition: TclObject.cc:152
void addListElement(const T &t)
Definition: TclObject.hh:128
zstring_view getString() const
Definition: TclObject.cc:120
constexpr double e
Definition: Math.hh:21
string expandTilde(string path)
Expand the '~' character to the users home directory.
const string & getUserDataDir()
Get the openMSX data dir in the user's home directory.
This file implemented 3 utility functions:
Definition: Autofire.cc:9
const FileContext & systemFileContext()
Definition: FileContext.cc:155
EventType getType(const Event &event)
Definition: Event.hh:647
FileContext userFileContext(string_view savePath)
Definition: FileContext.cc:171
TclObject makeTclDict(Args &&... args)
Definition: TclObject.hh:289
#define OUTER(type, member)
Definition: outer.hh:41
TemporaryString tmpStrCat(Ts &&... ts)
Definition: strCat.hh:610
constexpr auto xrange(T e)
Definition: xrange.hh:132