CAP/contrib/cvt2apple.c

397 lines
7.7 KiB
C

/*
* cvt2apple
*
* This program converts CAP/aufs style files to apple single or
* apple double format files (primarily for A/UX - you drag files
* from a client via aufs to a Unix volume than convert them to
* apple single format, then launch them using the A/UX launch
* utility).
*
* cvt2apple [-d] cap-file apple-file
*
* (if -d is specified an apple double file (pair) is created)
*
* Bugs: doesn't support icons from the desktop file
* (doesn't know how to find them :-(
*
* 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 <sys/types.h>
#include <stdio.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <netat/appletalk.h>
#include <netat/macfile.h>
#ifdef USEDIRENT
# include <dirent.h>
#else USEDIRENT
# ifdef xenix5
# include <sys/ndir.h>
# else xenix5
# include <sys/dir.h>
# endif xenix5
#endif USEDIRENT
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;
byte *comment;
FILE *fiopen();
FILE *fdata, *fresource, *ffinder;
main(argc, argv)
char **argv;
{
register struct hdr *hp;
register struct entry *ep;
int dbl;
unsigned dlen;
char *fin, *fout;
FILE *f;
register int i;
struct stat s;
dbl = 0;
hp = (struct hdr *)headers;
hp->nentries = 0;
ep = hp->entries;
/*
* validate the flags and input/output file
* names
*/
prog = argv[0];
if (argc < 3)
usage();
if (strcmp(argv[1], "-d") == 0) {
dbl = 1;
if (argc != 4)
usage();
fin = argv[2];
fout = argv[3];
} else {
if (argc > 3)
usage();
fin = argv[1];
fout = argv[2];
}
/*
* pick apart the input file name
*/
name_expand(fin);
/*
* try and open the CAP finder info
*/
ffinder = fiopen(dir, ".finderinfo/", file, "r");
if (ffinder) {
if (fread(&finfo, 1, sizeof(finfo), ffinder) < sizeof(OldFileInfo))
error("error reading finder info file");
ep->id = ID_FINDER;
ep->length = sizeof(finfo.fi_fndr);
ep++;
hp->nentries++;
if (finfo.fi_magic1 == FI_MAGIC1 &&
finfo.fi_magic == FI_MAGIC) {
ep->id = ID_COMMENT;
ep->length = finfo.fi_comln;
comment = finfo.fi_comnt;
ep++;
hp->nentries++;
} else {
ep->id = ID_COMMENT;
ep->length = ((OldFileInfo *)&finfo)->fi_comln;
comment = ((OldFileInfo *)&finfo)->fi_comnt;
ep++;
hp->nentries++;
}
}
/*
* try and open the CAP resource fork
*/
fresource = fiopen(dir, ".resource/", file, "r");
if (fresource) {
if (fstat(fileno(fresource), &s) >= 0) {
ep->id = ID_RESOURCE;
ep->length = s.st_size;
ep++;
hp->nentries++;
}
}
/*
* try and open the CAP data fork
*/
fdata = fiopen(dir, NULL, file, "r");
if (fdata) {
if (fstat(fileno(fdata), &s) >= 0) {
if (dbl) {
dlen = s.st_size;
} else {
ep->id = ID_DATA;
ep->length = s.st_size;
ep++;
hp->nentries++;
}
}
}
/*
* now pick apart the output name
*/
name_expand(fout);
if (dbl) {
/*
* for a double file copy the forks that are
* present, if nothing just give an empty data file
*/
if (hp->nentries == 0 && fdata == NULL)
error("cannot open %s", fin);
if (strlen(file) > MAXNAMLEN-1) {
fprintf(stderr,
"%s: warning: output file name more than %d characters '%s'\n",
prog, (MAXNAMLEN-1), fout);
}
if (fdata && (dlen > 0 || hp->nentries == 0)) {
f = fiopen(dir, NULL, file, "w");
if (f == NULL)
error("cannot create data fork %s", fout);
fcopy(f, fdata, dlen);
fclose(f);
}
if (hp->nentries) {
f = fiopen(dir, "%", file, "w");
if (f == NULL)
error("cannot create resource %s", fout);
write_single(f, hp, APPLE_DOUBLE);
fclose(f);
}
} else {
/*
* if a single file just copy it in
*/
if (hp->nentries == 0)
error("cannot open %s", fin);
f = fiopen(dir, NULL, file, "w");
if (f == NULL)
error("cannot open %s", fout);
write_single(f, hp, APPLE_SINGLE);
fclose(f);
}
}
/*
* 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 [-d] cap-file apple-file\n",
prog);
exit(1);
}
/*
* calculate a file header, write it out, then tack on
* all the contents
*
* on return: the header and entries are all converted to network
* order
*/
write_single(fout, hp, magic)
FILE *fout;
struct hdr *hp;
{
unsigned hsize, offset;
register struct entry *ep;
register int i;
int n;
dword el;
n = hp->nentries;
hsize = n*ENTRY_SIZE;
offset = hsize + HDR_SIZE;
for (i = 0, ep = hp->entries; i < n; i++, ep++) {
ep->id = htonl(ep->id); /* swap */
ep->offset = htonl(offset); /* swap */
offset += ep->length;
ep->length = htonl(ep->length); /* byte swap */
}
strncpy(hp->home, "Macintosh ", 16);
hp->magic = htonl(magic);
hp->version = htonl(VERSION);
hp->nentries = htons(n);
/* must do as two writes because of padding problems in way */
/* hdr is defined (double word aligment comes into play) */
if (fwrite(hp, 1, HDR_SIZE, fout) != HDR_SIZE)
error("error writing output file");
if (fwrite(hp->entries, 1, hsize, fout) != hsize)
error("error writing output file");
for (i = 0, ep = hp->entries; i < n; i++, ep++) {
el = htonl(ep->length);
switch(ntohl(ep->id)) {
case ID_DATA:
fcopy(fout, fdata, el);
break;
case ID_RESOURCE:
fcopy(fout, fresource, el);
break;
case ID_COMMENT:
if (el)
if (fwrite(comment, 1, el, fout) != el)
error("error writing output file");
break;
case ID_FINDER:
if (fwrite(finfo.fi_fndr, el, 1, fout) != 1)
error("error writing output file");
break;
}
}
}
/*
* 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--;
}
}