mirror of https://github.com/mabam/CAP.git
304 lines
6.1 KiB
C
304 lines
6.1 KiB
C
/*
|
|
* cvt2cap
|
|
*
|
|
* This program converts apple single or double files to CAP/aufs
|
|
* format files (primarily for A/UX).
|
|
*
|
|
* cvt2cap apple-file cap-file
|
|
*
|
|
* COPYRIGHT NOTICE
|
|
*
|
|
* Copyright (c) May 1988, Paul Campbell, All Rights Reserved.
|
|
*
|
|
* Permission is granted to any individual or institution to use, copy,
|
|
* or redistribute this software so long as it is not sold for profit,
|
|
* provided that this notice and the original copyright notices are
|
|
* retained. Paul Campbell makes no representations about the
|
|
* suitability of this software for any purpose. It is provided "as is"
|
|
* without express or implied warranty.
|
|
*
|
|
* History:
|
|
* 4/23/88 Paul Campbell, submitted to CAP distribution
|
|
* 4/23/88 Charlie C. Kim, clean up and modify to work with
|
|
* byte swapped machines
|
|
*
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <netinet/in.h>
|
|
#include <netat/appletalk.h>
|
|
#include <netat/macfile.h>
|
|
|
|
char *prog;
|
|
struct entry {
|
|
dword id;
|
|
dword offset;
|
|
dword length;
|
|
};
|
|
|
|
|
|
struct hdr {
|
|
dword magic;
|
|
dword version;
|
|
char home[16];
|
|
word nentries;
|
|
struct entry entries[1];
|
|
};
|
|
|
|
#define HDR_SIZE 26
|
|
#define ENTRY_SIZE sizeof(struct entry)
|
|
|
|
#define VERSION 0x00010000
|
|
#define APPLE_SINGLE 0x00051600
|
|
#define APPLE_DOUBLE 0x00051607
|
|
#define ID_DATA 1
|
|
#define ID_RESOURCE 2
|
|
#define ID_COMMENT 4
|
|
#define ID_FINDER 9
|
|
|
|
char dir[1025];
|
|
char file[1025];
|
|
char headers[1024];
|
|
FileInfo finfo;
|
|
|
|
FILE *fiopen();
|
|
|
|
main(argc, argv)
|
|
char **argv;
|
|
{
|
|
register struct hdr *hp;
|
|
register struct entry *ep;
|
|
char *fin, *fout;
|
|
FILE *f, *fd, *fx;
|
|
register int i, j;
|
|
int resource, data;
|
|
int retry;
|
|
char rname[33];
|
|
|
|
hp = (struct hdr *)headers;
|
|
bzero(&finfo, sizeof(finfo)); /* make sure clear first */
|
|
|
|
/*
|
|
* validate the flags and input/output file
|
|
* names
|
|
*/
|
|
|
|
prog = argv[0];
|
|
if (argc != 3)
|
|
usage();
|
|
fin = argv[1];
|
|
fout = argv[2];
|
|
|
|
name_expand(fin);
|
|
for (retry = 0;;retry++) {
|
|
switch(retry) {
|
|
case 0:
|
|
f = fiopen(dir, NULL, file, "r");
|
|
break;
|
|
case 1:
|
|
fd = f;
|
|
f = fiopen(dir, "%", file, "r");
|
|
break;
|
|
case 2:
|
|
error("Cannot find valid input file '%s'", fin);
|
|
}
|
|
if (f == NULL)
|
|
continue;
|
|
|
|
/*
|
|
* Read the header
|
|
*/
|
|
|
|
if (fread(hp, HDR_SIZE, 1, f) < 1)
|
|
continue;
|
|
if (ntohl(hp->magic) != APPLE_SINGLE &&
|
|
ntohl(hp->magic) != APPLE_DOUBLE)
|
|
continue;
|
|
if (ntohl(hp->version) != VERSION)
|
|
continue;
|
|
if (ntohl(hp->magic) == APPLE_DOUBLE &&
|
|
file[0] != '%' && retry != 1)
|
|
error("Apple double file name must begin with %% '%s'",
|
|
fin);
|
|
if (strncmp(hp->home, "Macintosh ", 16) != 0) {
|
|
hp->home[15] = 0;
|
|
error("Invalid file type '%s' in '%s'", hp->home, fin);
|
|
}
|
|
if (fread(hp->entries, ENTRY_SIZE, ntohs(hp->nentries), f) < 1)
|
|
continue;
|
|
break;
|
|
}
|
|
if (file[0] == '%') {
|
|
strncpy(rname, &file[1], 32);
|
|
} else {
|
|
strncpy(rname, file, 32);
|
|
}
|
|
|
|
data = 0;
|
|
resource = 0;
|
|
name_expand(fout);
|
|
for (i = 0, ep = hp->entries; i < (int)ntohs(hp->nentries); i++, ep++) {
|
|
switch(ntohl(ep->id)) {
|
|
case ID_DATA:
|
|
fx = fiopen(dir, NULL, file, "w");
|
|
if (fx == NULL)
|
|
error("Cannot create output data file '%s'", fout);
|
|
fseek(f, ntohl(ep->offset), 0);
|
|
fcopy(fx, f, ntohl(ep->length));
|
|
fclose(fx);
|
|
data = 1;
|
|
break;
|
|
|
|
case ID_RESOURCE:
|
|
fx = fiopen(dir, ".resource/", file, "w");
|
|
if (fx == NULL)
|
|
error("Cannot create output resource file '%s'",
|
|
fout);
|
|
fseek(f, ntohl(ep->offset), 0);
|
|
fcopy(fx, f, ntohl(ep->length));
|
|
fclose(fx);
|
|
resource = 1;
|
|
break;
|
|
|
|
case ID_COMMENT:
|
|
fseek(f, ntohl(ep->offset), 0);
|
|
j = ntohl(ep->length);
|
|
if (j > MAXCLEN)
|
|
j = MAXCLEN;
|
|
if (j > 0)
|
|
if (fread(finfo.fi_comnt, j, 1, f) < 1)
|
|
error("Couldn't read input file '%s'", fin);
|
|
finfo.fi_comln = j;
|
|
break;
|
|
|
|
case ID_FINDER:
|
|
fseek(f, ntohl(ep->offset), 0);
|
|
if (fread(finfo.fi_fndr, ntohl(ep->length), 1, f) < 1)
|
|
error("Couldn't read input file '%s'", fin);
|
|
break;
|
|
}
|
|
}
|
|
if (!data && hp->magic == APPLE_DOUBLE && fd) {
|
|
fseek(fd, 0, 0);
|
|
fx = fiopen(dir, NULL, file, "w");
|
|
if (fx == NULL)
|
|
error("Cannot create output data file '%s'", fout);
|
|
fcopy(fx, fd, ntohl(ep->length));
|
|
fclose(fx);
|
|
} else
|
|
if (!data) {
|
|
fx = fiopen(dir, NULL, file, "w");
|
|
if (fx == NULL)
|
|
error("Cannot create output data file '%s'", fout);
|
|
fclose(fx);
|
|
}
|
|
fx = fiopen(dir, ".finderinfo/", file, "w");
|
|
if (fx == NULL)
|
|
error("Cannot create output finder info file '%s'", fout);
|
|
finfo.fi_magic = FI_MAGIC;
|
|
finfo.fi_magic1 = FI_MAGIC1;
|
|
finfo.fi_version = FI_VERSION;
|
|
strcpy(finfo.fi_macfilename, rname);
|
|
finfo.fi_bitmap = FI_BM_MACINTOSHFILENAME;
|
|
if (fwrite(&finfo, sizeof(finfo), 1, fx) < 1)
|
|
error("Cannot write output finder info file '%s'", fout);
|
|
fclose(fx);
|
|
}
|
|
|
|
/*
|
|
* open the file "dir""ext""file" with mode "mode"
|
|
*/
|
|
|
|
FILE *
|
|
fiopen(dir, ext, file, mode)
|
|
char *dir, *ext, *file, *mode;
|
|
{
|
|
char name[1025];
|
|
|
|
strcpy(name, dir);
|
|
if (ext)
|
|
strcat(name, ext);
|
|
strcat(name, file);
|
|
return(fopen(name, mode));
|
|
}
|
|
|
|
/*
|
|
* print a nasty message
|
|
*/
|
|
|
|
usage()
|
|
{
|
|
fprintf(stderr, "Usage: %s apple-file cap-file\n",
|
|
prog);
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* copy length bytes from fin to fout
|
|
*/
|
|
|
|
fcopy(fout, fin, length)
|
|
FILE *fin, *fout;
|
|
unsigned length;
|
|
{
|
|
char buffer[4096];
|
|
register unsigned l;
|
|
|
|
for (;;) {
|
|
l = fread(buffer, 1, sizeof(buffer), fin);
|
|
if (l > length)
|
|
l = length;
|
|
if (l > 0) {
|
|
if (fwrite(buffer, 1, l, fout) != l)
|
|
error("error writing output file");
|
|
} else break;
|
|
length -= l;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* print another nasty message and quit
|
|
*/
|
|
|
|
error(s, a, b, c, d, e, f)
|
|
char *s;
|
|
{
|
|
fprintf(stderr, "%s: ", prog);
|
|
fprintf(stderr, s, a, b, c, d, e, f);
|
|
fprintf(stderr, "\n");
|
|
exit(2);
|
|
}
|
|
|
|
/*
|
|
* expand a file name to directory and filename parts
|
|
*/
|
|
|
|
name_expand(name)
|
|
char *name;
|
|
{
|
|
register char *cp;
|
|
|
|
strcpy(dir, name);
|
|
cp = &dir[strlen(dir)];
|
|
for (;;) {
|
|
if (*cp == '/') {
|
|
strcpy (file, cp+1);
|
|
*(cp+1) = 0;
|
|
if (file[0] == 0)
|
|
error("empty filename part in file name %s", name);
|
|
break;
|
|
}
|
|
if (cp == dir) {
|
|
strcpy(file, cp);
|
|
if (file[0] == 0)
|
|
error("empty filename part in file name %s", name);
|
|
strcpy(dir, "./");
|
|
break;
|
|
}
|
|
cp--;
|
|
}
|
|
}
|