mirror of
https://github.com/ksherlock/mpw.git
synced 2024-11-29 15:49:31 +00:00
349 lines
7.5 KiB
C++
349 lines
7.5 KiB
C++
/*
|
|
* Copyright (c) 2016, Kelvin W Sherlock
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
|
|
#include "native_internal.h"
|
|
#include <string>
|
|
#include <algorithm>
|
|
|
|
#include <cctype>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <strings.h>
|
|
|
|
using namespace MacOS;
|
|
|
|
namespace {
|
|
|
|
const long epoch_adjust = 86400 * (365 * (1970 - 1904) + 17); // 17 leap years.
|
|
|
|
|
|
std::string extension(const std::string &s)
|
|
{
|
|
std::string tmp;
|
|
int pos;
|
|
|
|
pos = s.find_last_of("./:");
|
|
|
|
if (pos == s.npos) return tmp;
|
|
if (s[pos++] != '.') return tmp;
|
|
if (pos >= s.length()) return tmp;
|
|
|
|
tmp = s.substr(pos);
|
|
|
|
std::transform(tmp.begin(), tmp.end(), tmp.begin(),
|
|
[](char c) { return tolower(c); }
|
|
);
|
|
|
|
return tmp;
|
|
}
|
|
|
|
std::string basename(const std::string &s)
|
|
{
|
|
int pos = s.find_last_of("/:");
|
|
if (pos == s.npos) return s;
|
|
|
|
return s.substr(pos + 1);
|
|
}
|
|
|
|
unsigned tox(unsigned x)
|
|
{
|
|
if (x >= '0' && x <= '9') return x - '0';
|
|
if (x >= 'a' && x <= 'f') return x - 'a' + 10;
|
|
if (x >= 'A' && x <= 'F') return x - 'A' + 10;
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
namespace native {
|
|
|
|
|
|
uint32_t unix_to_mac(time_t t) {
|
|
if (!t) return 0;
|
|
return t + epoch_adjust;
|
|
}
|
|
|
|
time_t mac_to_unix(uint32_t t) {
|
|
if (!t) return 0;
|
|
return t - epoch_adjust;
|
|
}
|
|
|
|
void prodos_ftype_out(uint8_t *buffer) {
|
|
if (memcmp(buffer + 4, "pdos", 4) == 0) {
|
|
// mpw expects 'xx ' where
|
|
// xx are the ascii-encode hex value of the file type.
|
|
// the hfs fst uses 'p' ftype8 auxtype16
|
|
|
|
// todo -- but only if auxtype is $0000 ??
|
|
if (buffer[0] == 'p' && buffer[2] == 0 && buffer[3] == 0)
|
|
{
|
|
static char Hex[] = "0123456789ABCDEF";
|
|
|
|
uint8_t ftype = buffer[1];
|
|
buffer[0] = Hex[ftype >> 4];
|
|
buffer[1] = Hex[ftype & 0x0f];
|
|
buffer[2] = ' ';
|
|
buffer[3] = ' ';
|
|
}
|
|
}
|
|
}
|
|
|
|
void prodos_ftype_in(uint8_t *buffer) {
|
|
if (::memcmp(buffer + 2, " pdos", 6) == 0)
|
|
{
|
|
unsigned a = buffer[0];
|
|
unsigned b = buffer[1];
|
|
|
|
if (isxdigit(a) && isxdigit(b))
|
|
{
|
|
buffer[0] = 'p';
|
|
buffer[1] = (tox(a) << 4) | tox(b);
|
|
buffer[2] = 0;
|
|
buffer[3] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
macos_error get_finder_info(const std::string &path_name, uint32_t &ftype, uint32_t &ctype) {
|
|
|
|
uint8_t buffer[16];
|
|
|
|
auto err = get_finder_info(path_name, buffer, false);
|
|
if (err) return err;
|
|
|
|
return noErr;
|
|
ftype = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3] << 0);
|
|
ctype = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0);
|
|
|
|
}
|
|
|
|
|
|
macos_error set_finder_info(const std::string &path_name, uint32_t ftype, uint32_t ctype) {
|
|
|
|
uint8_t buffer[32];
|
|
std::memset(buffer, 0, sizeof(buffer));
|
|
|
|
buffer[0] = ftype >> 24;
|
|
buffer[1] = ftype >> 16;
|
|
buffer[2] = ftype >> 8;
|
|
buffer[3] = ftype >> 0;
|
|
|
|
buffer[4] = ctype >> 24;
|
|
buffer[5] = ctype >> 16;
|
|
buffer[6] = ctype >> 8;
|
|
buffer[7] = ctype >> 0;
|
|
|
|
return set_finder_info(path_name, buffer, true);
|
|
}
|
|
|
|
|
|
bool is_text_file_internal(const std::string &path_name) {
|
|
|
|
std::string ext = extension(path_name);
|
|
if (ext.empty()) return false;
|
|
|
|
char c = ext[0];
|
|
switch(c)
|
|
{
|
|
case 'a':
|
|
if (ext == "aii") // assembler
|
|
return true;
|
|
if (ext == "asm")
|
|
return true;
|
|
break;
|
|
|
|
case 'c':
|
|
if (ext == "c")
|
|
return true;
|
|
if (ext == "cpp")
|
|
return true;
|
|
break;
|
|
|
|
case 'e':
|
|
if (ext == "equ") // asm iigs include file.
|
|
return true;
|
|
if (ext == "equates") // asm iigs include file.
|
|
return true;
|
|
break;
|
|
|
|
case 'i':
|
|
if (ext == "i") // asmiigs include file
|
|
return true;
|
|
if (ext == "inc")
|
|
return true;
|
|
break;
|
|
|
|
case 'h':
|
|
if (ext == "h") // c header
|
|
return true;
|
|
break;
|
|
|
|
case 'l':
|
|
if (ext == "lst") // asm iigs listing
|
|
return true;
|
|
break;
|
|
|
|
case 'm':
|
|
if (ext == "macros")
|
|
return true;
|
|
break;
|
|
|
|
case 'p':
|
|
if (ext == "p") // pascal
|
|
return true;
|
|
if (ext == "pas") // pascal
|
|
return true;
|
|
if (ext == "pii") // pascal
|
|
return true;
|
|
break;
|
|
|
|
case 'r':
|
|
if (ext == "r")
|
|
return true;
|
|
if (ext == "rez")
|
|
return true;
|
|
if (ext == "rii") // rez
|
|
return true;
|
|
break;
|
|
|
|
case 's':
|
|
if (ext == "src") // asm equates
|
|
return true;
|
|
break;
|
|
|
|
}
|
|
|
|
// check for e16.xxxx or m16.xxxx
|
|
ext = basename(path_name);
|
|
if (ext.length() > 4)
|
|
{
|
|
switch (ext[0])
|
|
{
|
|
case 'm':
|
|
case 'M':
|
|
case 'e':
|
|
case 'E':
|
|
if (!strncmp("16.", ext.c_str() + 1, 3))
|
|
return true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool is_binary_file_internal(const std::string &path_name) {
|
|
|
|
std::string ext = extension(path_name);
|
|
if (ext.empty()) return false;
|
|
|
|
char c = ext[0];
|
|
switch(c)
|
|
{
|
|
case 'l':
|
|
if (ext == "lib")
|
|
return true;
|
|
break;
|
|
|
|
case 'n':
|
|
// MrC / MrCpp temp file.
|
|
if (ext == "n")
|
|
return true;
|
|
// Newton C++ Tools output
|
|
if (ext == "ntkc")
|
|
return true;
|
|
break;
|
|
|
|
case 'o':
|
|
if (ext == "o")
|
|
return true;
|
|
if (ext == "obj")
|
|
return true;
|
|
break;
|
|
|
|
case 's':
|
|
// Newton C++ Intermediate file
|
|
if (ext == "sym")
|
|
return true;
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool is_text_file(const std::string &path_name) {
|
|
|
|
uint32_t ftype, ctype;
|
|
|
|
auto err = get_finder_info(path_name, ftype, ctype);
|
|
if (!err) return ftype == 'TEXT';
|
|
|
|
return is_text_file_internal(path_name);
|
|
}
|
|
|
|
bool is_binary_file(const std::string &path_name) {
|
|
|
|
uint32_t ftype, ctype;
|
|
|
|
auto err = get_finder_info(path_name, ftype, ctype);
|
|
if (!err) {
|
|
if (ctype == 'pdos') {
|
|
// 'Bx '
|
|
if ((ftype & 0xf0ff) == 'B\x00 ') return true;
|
|
/* really, anything not TEXT is binary... */
|
|
if ((ftype & 0xf000) == 'p') return true;
|
|
//if (ftype >= 'p\xb1\x00\x00' && ftype <= 'p\xbf\xff\xff') return true;
|
|
//if (ftype == 'PSYS' || ftype == 'PS16') return true;
|
|
}
|
|
if (ftype == 'BINA') return true;
|
|
}
|
|
|
|
return is_text_file_internal(path_name);
|
|
|
|
}
|
|
|
|
int open_fork(const std::string &path_name, int fork, int oflag, int perm) {
|
|
|
|
if (!fork) return ::open(path_name.c_str(), oflag, perm);
|
|
|
|
// if O_CREAT or E_EXCL, may need to create the file
|
|
|
|
int tmp = oflag & (O_CREAT | O_EXCL);
|
|
if (tmp) {
|
|
int fd = ::open(path_name.c_str(), (oflag & O_ACCMODE) | tmp, perm);
|
|
if (fd < 0) return fd;
|
|
::close(fd);
|
|
oflag &= ~ (O_CREAT | O_EXCL);
|
|
}
|
|
return open_resource_fork(path_name, oflag);
|
|
}
|
|
|
|
|
|
}
|