Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Builder/Android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@
<data android:pathPattern=".*\\.D88" />
<data android:host="*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.m3u" />
<data android:pathPattern=".*\\.M3U" />
<data android:pathPattern=".*\\.m3u8" />
<data android:pathPattern=".*\\.M3U8" />
<data android:host="*" />
</intent-filter>
</activity>
</application>
</manifest>
1 change: 1 addition & 0 deletions Builder/Linux/xm8.desktop
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ GenericName=XM8
Comment=PC-8801MA Emulator
Comment[ja]=PC-8801MA エミュレーター
Exec=xm8
MimeType=application/x-m3u;audio/x-mpegurl;application/vnd.apple.mpegurl;
Icon=xm8
Terminal=false
Type=Application
Expand Down
8 changes: 8 additions & 0 deletions Builder/macOS/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@
<string>????</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key><string>XM8 Disk and Playlist</string>
<key>CFBundleTypeRole</key><string>Viewer</string>
<key>CFBundleTypeExtensions</key><array><string>d88</string><string>m3u</string><string>m3u8</string></array>
</dict>
</array>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
Expand Down
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ option(ENABLE_PACKAGING "Enable CPack packaging" ON)
target_link_libraries(${BIN_TARGET} PRIVATE XM8::SDL xbrz)
if(APPLE)
target_link_libraries(${BIN_TARGET} PRIVATE "-framework Foundation")
find_library(XM8_ICONV_LIBRARY iconv REQUIRED)
target_link_libraries(${BIN_TARGET} PRIVATE ${XM8_ICONV_LIBRARY})
endif()

if(BUILD_TESTING)
Expand All @@ -245,6 +247,9 @@ if(BUILD_TESTING)
Source/UI/m3u.cpp
)
target_include_directories(clidisk_test PRIVATE Source/UI)
if(APPLE)
target_link_libraries(clidisk_test PRIVATE ${XM8_ICONV_LIBRARY})
endif()
add_test(NAME clidisk_test COMMAND clidisk_test)

add_executable(d88probe_test
Expand Down Expand Up @@ -406,6 +411,9 @@ if(BUILD_TESTING)
$<TARGET_OBJECTS:xm8_ra_media_xm8>
)
target_link_libraries(ra_dependency_test PRIVATE xm8_ra_dependencies)
if(APPLE)
target_link_libraries(ra_dependency_test PRIVATE ${XM8_ICONV_LIBRARY})
endif()
target_include_directories(ra_dependency_test PRIVATE Source/RA Source/UI)
target_compile_definitions(ra_dependency_test PRIVATE
XM8_ENABLE_RETROACHIEVEMENTS=1)
Expand Down
52 changes: 51 additions & 1 deletion Source/UI/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "diskmgr.h"
#include "tapemgr.h"
#include "clidisk.h"
#include "m3u.h"
#ifdef XM8_ENABLE_RETROACHIEVEMENTS
#include "ra_media_change_policy.h"
#include "ra_build_info.h"
Expand Down Expand Up @@ -1110,6 +1111,38 @@ bool App::OpenDiskPairFromMenu(const std::string& path, bool *drive2_open,
return true;
}

bool App::OpenDiskSpecsFromMenu(const std::vector<DiskSpec>& specs,
std::string *error, bool close_drive2)
{
struct Snapshot { bool open; std::string path; int bank; } snapshots[MAX_DRIVE];
int banks;
if (specs.empty() || specs.size() > MAX_DRIVE) {
*error = "invalid disk selection";
return false;
}
for (const DiskSpec& spec : specs)
if (!ProbeDisk(spec, &banks, error)) return false;
for (int drive = 0; drive < MAX_DRIVE; ++drive) {
snapshots[drive].open = diskmgr[drive]->IsOpen();
if (snapshots[drive].open) {
snapshots[drive].path = diskmgr[drive]->GetPath();
snapshots[drive].bank = diskmgr[drive]->GetBank();
}
}
auto restore = [this, &snapshots]() {
for (int drive = 0; drive < MAX_DRIVE; ++drive) {
if (snapshots[drive].open) diskmgr[drive]->Open(snapshots[drive].path.c_str(), snapshots[drive].bank);
else diskmgr[drive]->Close();
}
};
for (const DiskSpec& spec : specs) {
if (!OpenDiskFromUser(spec, error)) { restore(); return false; }
}
if (close_drive2) diskmgr[1]->Close();
RememberDiskOpenDir(specs.front().path.c_str());
return true;
}

#ifdef XM8_ENABLE_RETROACHIEVEMENTS
//
// ResolveDiskForRaMode()
Expand Down Expand Up @@ -4207,12 +4240,20 @@ bool App::OpenDroppedDisk(const char *path, std::string *error)
int bank;
};
Snapshot snapshots[MAX_DRIVE];
DiskSpec first = {path, 0, 0};
std::vector<DiskSpec> playlist_specs;
if (IsM3UPath(path) && !LoadPlaylistDiskSpecs(path, 0, MAX_DRIVE,
&playlist_specs, error)) return false;
DiskSpec first = playlist_specs.empty() ? DiskSpec{path, 0, 0} : playlist_specs[0];
int banks;

if (ProbeDisk(first, &banks, error) == false) {
return false;
}
if (!playlist_specs.empty()) {
for (const DiskSpec& spec : playlist_specs) {
if (ProbeDisk(spec, &banks, error) == false) return false;
}
}
for (int drive=0; drive<MAX_DRIVE; drive++) {
snapshots[drive].open = diskmgr[drive]->IsOpen();
if (snapshots[drive].open) {
Expand All @@ -4236,6 +4277,15 @@ bool App::OpenDroppedDisk(const char *path, std::string *error)
restore();
return false;
}
if (!playlist_specs.empty()) {
if (playlist_specs.size() > 1 &&
!OpenDiskFromUser(playlist_specs[1], error)) {
restore();
return false;
}
if (playlist_specs.size() == 1) diskmgr[1]->Close();
return true;
}
if (banks > 1) {
DiskSpec second = {path, 1, 1};
if (OpenDiskFromUser(second, error) == false) {
Expand Down
2 changes: 2 additions & 0 deletions Source/UI/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ class App
bool OpenDiskPairFromMenu(const std::string& path, bool *drive2_open,
std::string *error);
// open bank 0/1 as one transaction
bool OpenDiskSpecsFromMenu(const std::vector<DiskSpec>& specs,
std::string *error, bool close_drive2 = false);
const char* GetTapeDir();
// get tape dir
void Reset();
Expand Down
65 changes: 29 additions & 36 deletions Source/UI/clidisk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ bool ParseBank(const std::string& value, int *bank)
return true;
}

bool ParseDiskSpec(const std::string& argument, int drive, DiskSpec *spec,
bool ParseDiskSpecInternal(const std::string& argument, int drive, DiskSpec *spec,
std::string *error)
{
const std::string::size_type slash = argument.find_last_of("/\\");
Expand Down Expand Up @@ -120,17 +120,31 @@ bool ParseClock(const std::string& value, CliClockMode *clock)
return true;
}

bool IsM3U(const std::string& path)
{
if (path.length() < 4) {
return false;
}
} // namespace

std::string ext = ToUpper(path.substr(path.length() - 4));
return ext == ".M3U";
bool ParseDiskSpec(const std::string& argument, int drive, DiskSpec *spec,
std::string *error)
{
return ParseDiskSpecInternal(argument, drive, spec, error);
}

} // namespace
bool LoadPlaylistDiskSpecs(const std::string& path, int first_drive,
size_t maximum, std::vector<DiskSpec> *specs, std::string *error)
{
if (specs == nullptr || error == nullptr) return false;
M3UResult playlist = LoadM3U(path);
if (!playlist.success) { *error = playlist.error; return false; }
specs->clear();
for (const std::string& entry : playlist.entries) {
if (specs->size() >= maximum) break;
DiskSpec spec;
if (!ParseDiskSpec(entry, first_drive + static_cast<int>(specs->size()),
&spec, error)) return false;
specs->push_back(spec);
}
if (specs->empty()) { *error = "playlist contains no disk images: " + path; return false; }
return true;
}

CliOptions ParseCommandLine(int argc, char *argv[])
{
Expand Down Expand Up @@ -198,33 +212,12 @@ CliOptions ParseCommandLine(int argc, char *argv[])
return Error("too many disk images; maximum is 2");
}

if (IsM3U(argument)) {

M3UResult playlist = LoadM3U(argument);

if (!playlist.success) {
return Error(playlist.error);
}

for (const auto& entry : playlist.entries) {

if (options.disks.size() >=2) {
break;
}

DiskSpec spec;
std::string error;

if (!ParseDiskSpec(entry,
static_cast<int>(options.disks.size()),
&spec,
&error)) {
return Error(error);
}

options.disks.push_back(spec);
}

if (IsM3UPath(argument)) {
std::vector<DiskSpec> specs;
std::string error;
if (!LoadPlaylistDiskSpecs(argument, static_cast<int>(options.disks.size()),
2 - options.disks.size(), &specs, &error)) return Error(error);
options.disks.insert(options.disks.end(), specs.begin(), specs.end());
} else {

DiskSpec spec;
Expand Down
4 changes: 4 additions & 0 deletions Source/UI/clidisk.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,9 @@ struct CliOptions {

CliOptions ParseCommandLine(int argc, char *argv[]);
const char* GetCommandLineHelp();
bool ParseDiskSpec(const std::string& argument, int drive, DiskSpec *spec,
std::string *error);
bool LoadPlaylistDiskSpecs(const std::string& path, int first_drive,
size_t maximum, std::vector<DiskSpec> *specs, std::string *error);

#endif
Loading
Loading