From 507ba9debff391d24885fc7ff46127453b3c3e64 Mon Sep 17 00:00:00 2001 From: Wolfgang Thaller Date: Wed, 4 Oct 2017 02:03:26 +0200 Subject: [PATCH] LaunchAPPL --make-executable: add a #!/.../LaunchCFMApp to a mac app --- LaunchAPPL/CMakeLists.txt | 1 + LaunchAPPL/LaunchAPPL.cc | 23 ++++++++++++++-- LaunchAPPL/MakeExecutable.cc | 52 +++++++++++++++++++++++++++++++++++ ResourceFiles/ResourceFile.cc | 21 ++++++++++++++ ResourceFiles/ResourceFile.h | 3 ++ 5 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 LaunchAPPL/MakeExecutable.cc diff --git a/LaunchAPPL/CMakeLists.txt b/LaunchAPPL/CMakeLists.txt index 30e846322d..ce0bc61630 100644 --- a/LaunchAPPL/CMakeLists.txt +++ b/LaunchAPPL/CMakeLists.txt @@ -20,6 +20,7 @@ add_definitions(-DRETRO68_PREFIX="${CMAKE_INSTALL_PREFIX}") add_executable(LaunchAPPL LaunchAPPL.cc + MakeExecutable.cc LaunchMethod.h LaunchMethod.cc Launcher.h Launcher.cc diff --git a/LaunchAPPL/LaunchAPPL.cc b/LaunchAPPL/LaunchAPPL.cc index 38f391b9d6..af532d75ea 100644 --- a/LaunchAPPL/LaunchAPPL.cc +++ b/LaunchAPPL/LaunchAPPL.cc @@ -93,7 +93,7 @@ static void usage() } } - +void MakeExecutable(string filepath); int main(int argc, char *argv[]) { @@ -102,6 +102,7 @@ int main(int argc, char *argv[]) desc.add_options() ("help,h", "show this help message") + ("make-executable,x", po::value(), "make a MacBinary file executable") ; po::options_description configdesc; configdesc.add_options() @@ -158,12 +159,28 @@ int main(int argc, char *argv[]) po::notify(options); - if(options.count("help") || !options.count("application") || !options.count("emulator")) + if(options.count("help") || (!options.count("application") && !options.count("make-executable"))) { usage(); return 0; } + if(options.count("make-executable")) + { + string fn = options["make-executable"].as(); + MakeExecutable(fn); + + if(!options.count("application")) + return 0; + } + + if(!options.count("emulator")) + { + std::cerr << "ERROR: emulator/environment not specified.\n"; + usage(); + return 1; + } + LaunchMethod *method = NULL; for(LaunchMethod *lm : launchMethods) { @@ -181,7 +198,7 @@ int main(int argc, char *argv[]) if(!method->CheckOptions(options)) { - std::cerr << "Missing configuration.\n"; + std::cerr << "Need more configuration.\n"; usage(); return 1; } diff --git a/LaunchAPPL/MakeExecutable.cc b/LaunchAPPL/MakeExecutable.cc new file mode 100644 index 0000000000..b2f08304b5 --- /dev/null +++ b/LaunchAPPL/MakeExecutable.cc @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +#include "ResourceFile.h" + +using std::string; +namespace fs = boost::filesystem; + +void MakeExecutable(string fn) +{ + ResourceFile rsrcFile(fn); + if(!rsrcFile.read()) + { + std::cerr << "Cannot read application file: " << fn << std::endl; + exit(1); + } + if(!rsrcFile.hasPlainDataFork()) + { + std::cerr << "--make-executable can not be used with this data format.\n"; + exit(1); + } + + string headerString = "#!" RETRO68_PREFIX "/bin/LaunchAPPL\n"; + + bool hadShebang = false; + if(rsrcFile.data.size()) + { + if(headerString.substr(2) == "#!") + { + string::size_type eol = headerString.find('\n'); + if(eol != string::npos && eol >= 13 && eol < 4096) + { + if(headerString.substr(eol-11,11) == "/LaunchAPPL") + hadShebang = true; + } + } + + if(!hadShebang) + { + std::cerr << "Unfortunately, the application already has a data fork.\n"; + std::cerr << "LaunchAPPL --make-executable does not currently work for PowerPC apps.\n"; + // TODO: if it's a PEF container, move it back a little and update cfrg + exit(1); + } + } + + std::fstream(fn, std::ios::in | std::ios::out | std::ios::binary) << headerString; + + fs::permissions(fs::path(fn), fs::owner_exe | fs::group_exe | fs::others_exe | fs::add_perms); +} diff --git a/ResourceFiles/ResourceFile.cc b/ResourceFiles/ResourceFile.cc index 7021566ee1..fb86aef9f4 100644 --- a/ResourceFiles/ResourceFile.cc +++ b/ResourceFiles/ResourceFile.cc @@ -523,3 +523,24 @@ bool ResourceFile::write() return true; } +bool ResourceFile::hasPlainDataFork(ResourceFile::Format f) +{ + switch(f) + { +#ifdef __APPLE__ + case Format::real: +#endif + case Format::basilisk: + case Format::underscore_appledouble: + case Format::percent_appledouble: + return true; + default: + return false; + } +} + +bool ResourceFile::hasPlainDataFork() +{ + return hasPlainDataFork(format); +} + diff --git a/ResourceFiles/ResourceFile.h b/ResourceFiles/ResourceFile.h index f31dd4e319..00cea3f0f6 100644 --- a/ResourceFiles/ResourceFile.h +++ b/ResourceFiles/ResourceFile.h @@ -31,6 +31,9 @@ public: bool read(); bool write(); + static bool hasPlainDataFork(Format f); + bool hasPlainDataFork(); + std::string pathstring; Format format; ResType type;