LaunchAPPL: support reading MacBinary from stdin

This commit is contained in:
Wolfgang Thaller 2017-10-08 22:23:08 +02:00
parent 19277b3d2e
commit 0e2eb677e4
3 changed files with 167 additions and 105 deletions

View File

@ -1,6 +1,7 @@
#include "Launcher.h" #include "Launcher.h"
#include <boost/filesystem/fstream.hpp> #include <boost/filesystem/fstream.hpp>
#include <iostream> #include <iostream>
#include <sstream>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
@ -14,9 +15,21 @@ using std::vector;
Launcher::Launcher(boost::program_options::variables_map &options) Launcher::Launcher(boost::program_options::variables_map &options)
: options(options) : options(options)
{ {
app.assign(options["application"].as<std::string>()); string fn = options["application"].as<std::string>();
if(fn == "-")
{
std::stringstream tmp;
tmp << std::cin.rdbuf();
if(!app.read(tmp, ResourceFile::Format::macbin))
throw std::runtime_error("Could not load application from stdin.");
}
else
{
app.assign(fn);
if(!app.read()) if(!app.read())
throw std::runtime_error("Could not load application file."); throw std::runtime_error("Could not load application file.");
}
tempDir = fs::absolute(fs::unique_path()); tempDir = fs::absolute(fs::unique_path());
fs::create_directories(tempDir); fs::create_directories(tempDir);

View File

@ -150,6 +150,7 @@ bool ResourceFile::assign(std::string pathstring, ResourceFile::Format f)
this->pathstring = pathstring; this->pathstring = pathstring;
fs::path path(pathstring); fs::path path(pathstring);
this->filename = path.stem().string();
fs::path rsrcPath = path.parent_path() / ".rsrc" / path.filename(); fs::path rsrcPath = path.parent_path() / ".rsrc" / path.filename();
fs::path finfPath = path.parent_path() / ".finf" / path.filename(); fs::path finfPath = path.parent_path() / ".finf" / path.filename();
@ -208,12 +209,91 @@ bool ResourceFile::assign(std::string pathstring, ResourceFile::Format f)
return true; return true;
} }
bool ResourceFile::read(std::istream& in, Format f)
{
switch(f)
{
case Format::applesingle:
{
if(longword(in) != 0x00051600)
return false;
if(longword(in) != 0x00020000)
return false;
in.seekg(24);
int n = word(in);
for(int i = 0; i < n; i++)
{
in.seekg(26 + i * 12);
int what = longword(in);
int off = longword(in);
int len = longword(in);
in.seekg(off);
switch(what)
{
case 1:
{
std::vector<char> buf(len);
in.read(buf.data(), len);
data = std::string(buf.begin(), buf.end());
}
break;
case 2:
resources = Resources(in);
break;
case 9:
type = ostype(in);
creator = ostype(in);
break;
}
}
}
break;
case Format::macbin:
{
if(byte(in) != 0)
return false;
if(byte(in) > 63)
return false;
in.seekg(65);
type = ostype(in);
creator = ostype(in);
in.seekg(83);
int datasize = longword(in);
//int rsrcsize = longword(in);
in.seekg(0);
char header[124];
in.read(header, 124);
unsigned short crc = CalculateCRC(0,header,124);
if(word(in) != crc)
return false;
in.seekg(128);
std::vector<char> buf(datasize);
in.read(buf.data(), datasize);
data = std::string(buf.begin(), buf.end());
datasize = ((int)datasize + 0x7F) & ~0x7F;
in.seekg(128 + datasize);
resources = Resources(in);
}
break;
default:
return false;
}
return true;
}
bool ResourceFile::read() bool ResourceFile::read()
{ {
fs::path path(pathstring); fs::path path(pathstring);
type = creator = 0x3F3F3F3F; type = creator = 0x3F3F3F3F;
if(isSingleFork(format))
{
fs::ifstream in(path);
return read(in, format);
}
switch(format) switch(format)
{ {
case Format::basilisk: case Format::basilisk:
@ -259,42 +339,7 @@ bool ResourceFile::read()
} }
break; break;
#endif #endif
case Format::applesingle:
{
fs::ifstream in(path);
if(longword(in) != 0x00051600)
return false;
if(longword(in) != 0x00020000)
return false;
in.seekg(24);
int n = word(in);
for(int i = 0; i < n; i++)
{
in.seekg(26 + i * 12);
int what = longword(in);
int off = longword(in);
int len = longword(in);
in.seekg(off);
switch(what)
{
case 1:
{
std::vector<char> buf(len);
in.read(buf.data(), len);
data = std::string(buf.begin(), buf.end());
}
break;
case 2:
resources = Resources(in);
break;
case 9:
type = ostype(in);
creator = ostype(in);
break;
}
}
}
break;
case Format::underscore_appledouble: case Format::underscore_appledouble:
case Format::percent_appledouble: case Format::percent_appledouble:
{ {
@ -333,33 +378,50 @@ bool ResourceFile::read()
} }
} }
break; break;
default:
return false;
}
return true;
}
bool ResourceFile::write(std::ostream& out, Format f)
{
switch(f)
{
case Format::macbin: case Format::macbin:
{ {
fs::ifstream in(path); writeMacBinary(out, filename, type, creator, resources, data);
if(byte(in) != 0) }
return false; break;
if(byte(in) > 63) case Format::applesingle:
return false; {
in.seekg(65); longword(out, 0x00051600);
type = ostype(in); longword(out, 0x00020000);
creator = ostype(in); for(int i = 0; i < 16; i++)
in.seekg(83); byte(out, 0);
int datasize = longword(in); word(out, 3);
//int rsrcsize = longword(in); std::streampos entries = out.tellp();
for(int i = 0; i < 3*3; i++)
in.seekg(0); longword(out, 0);
char header[124]; std::streampos dataStart = out.tellp();
in.read(header, 124); out << data;
unsigned short crc = CalculateCRC(0,header,124); std::streampos rsrcStart = out.tellp();
if(word(in) != crc) resources.writeFork(out);
return false; std::streampos finfStart = out.tellp();
in.seekg(128); ostype(out, type);
std::vector<char> buf(datasize); ostype(out, creator);
in.read(buf.data(), datasize); for(int i = 8; i < 32; i++)
data = std::string(buf.begin(), buf.end()); byte(out, 0);
datasize = ((int)datasize + 0x7F) & ~0x7F; out.seekp(entries);
in.seekg(128 + datasize); longword(out, 1);
resources = Resources(in); longword(out, dataStart);
longword(out, rsrcStart - dataStart);
longword(out, 2);
longword(out, rsrcStart);
longword(out, finfStart - rsrcStart);
longword(out, 9);
longword(out, finfStart);
longword(out, 32);
} }
break; break;
default: default:
@ -372,6 +434,12 @@ bool ResourceFile::write()
{ {
fs::path path(pathstring); fs::path path(pathstring);
if(isSingleFork(format))
{
fs::ofstream out(path);
return write(out, format);
}
switch(format) switch(format)
{ {
case Format::basilisk: case Format::basilisk:
@ -411,46 +479,7 @@ bool ResourceFile::write()
} }
break; break;
#endif #endif
case Format::macbin:
{
fs::ofstream out(path);
writeMacBinary(out, path.stem().string(), type, creator, resources, data);
}
break;
case Format::applesingle:
{
fs::ofstream out(path);
longword(out, 0x00051600);
longword(out, 0x00020000);
for(int i = 0; i < 16; i++)
byte(out, 0);
word(out, 3);
std::streampos entries = out.tellp();
for(int i = 0; i < 3*3; i++)
longword(out, 0);
std::streampos dataStart = out.tellp();
out << data;
std::streampos rsrcStart = out.tellp();
resources.writeFork(out);
std::streampos finfStart = out.tellp();
ostype(out, type);
ostype(out, creator);
for(int i = 8; i < 32; i++)
byte(out, 0);
out.seekp(entries);
longword(out, 1);
longword(out, dataStart);
longword(out, rsrcStart - dataStart);
longword(out, 2);
longword(out, rsrcStart);
longword(out, finfStart - rsrcStart);
longword(out, 9);
longword(out, finfStart);
longword(out, 32);
}
break;
// TODO: case Format::underscore_appledouble
case Format::underscore_appledouble: case Format::underscore_appledouble:
case Format::percent_appledouble: case Format::percent_appledouble:
{ {
@ -548,3 +577,14 @@ bool ResourceFile::hasPlainDataFork()
return hasPlainDataFork(format); return hasPlainDataFork(format);
} }
bool ResourceFile::isSingleFork(Format f)
{
switch(f)
{
case Format::macbin:
case Format::applesingle:
return true;
default:
return false;
}
}

View File

@ -2,6 +2,9 @@
#define RESOURCEFILE_H #define RESOURCEFILE_H
#include <memory> #include <memory>
#include <iosfwd>
#include <string>
#include "ResType.h" #include "ResType.h"
#include "ResourceFork.h" #include "ResourceFork.h"
@ -28,13 +31,19 @@ public:
bool assign(std::string path, Format f = Format::autodetect); bool assign(std::string path, Format f = Format::autodetect);
bool read(std::istream& in, Format f);
bool write(std::ostream& in, Format f);
bool read(); bool read();
bool write(); bool write();
static bool hasPlainDataFork(Format f); static bool hasPlainDataFork(Format f);
bool hasPlainDataFork(); bool hasPlainDataFork();
static bool isSingleFork(Format f);
std::string pathstring; std::string pathstring;
std::string filename;
Format format; Format format;
ResType type; ResType type;
ResType creator; ResType creator;