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 <boost/filesystem/fstream.hpp>
#include <iostream>
#include <sstream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
@ -14,10 +15,22 @@ using std::vector;
Launcher::Launcher(boost::program_options::variables_map &options)
: options(options)
{
app.assign(options["application"].as<std::string>());
if(!app.read())
throw std::runtime_error("Could not load application file.");
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())
throw std::runtime_error("Could not load application file.");
}
tempDir = fs::absolute(fs::unique_path());
fs::create_directories(tempDir);

View File

@ -150,6 +150,7 @@ bool ResourceFile::assign(std::string pathstring, ResourceFile::Format f)
this->pathstring = pathstring;
fs::path path(pathstring);
this->filename = path.stem().string();
fs::path rsrcPath = path.parent_path() / ".rsrc" / 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;
}
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()
{
fs::path path(pathstring);
type = creator = 0x3F3F3F3F;
if(isSingleFork(format))
{
fs::ifstream in(path);
return read(in, format);
}
switch(format)
{
case Format::basilisk:
@ -259,42 +339,7 @@ bool ResourceFile::read()
}
break;
#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::percent_appledouble:
{
@ -333,33 +378,50 @@ bool ResourceFile::read()
}
}
break;
default:
return false;
}
return true;
}
bool ResourceFile::write(std::ostream& out, Format f)
{
switch(f)
{
case Format::macbin:
{
fs::ifstream in(path);
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);
writeMacBinary(out, filename, type, creator, resources, data);
}
break;
case Format::applesingle:
{
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;
default:
@ -372,6 +434,12 @@ bool ResourceFile::write()
{
fs::path path(pathstring);
if(isSingleFork(format))
{
fs::ofstream out(path);
return write(out, format);
}
switch(format)
{
case Format::basilisk:
@ -411,46 +479,7 @@ bool ResourceFile::write()
}
break;
#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::percent_appledouble:
{
@ -548,3 +577,14 @@ bool ResourceFile::hasPlainDataFork()
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
#include <memory>
#include <iosfwd>
#include <string>
#include "ResType.h"
#include "ResourceFork.h"
@ -28,13 +31,19 @@ public:
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 write();
static bool hasPlainDataFork(Format f);
bool hasPlainDataFork();
static bool isSingleFork(Format f);
std::string pathstring;
std::string filename;
Format format;
ResType type;
ResType creator;