home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Amiga / Workbench / Archivers / mpackPPC.lha / mpackPPC / src / macfile.c < prev    next >
C/C++ Source or Header  |  1998-04-08  |  11KB  |  338 lines

  1. /* macfile.c -- simple applesingle/appledouble encoding/decoding routines
  2.  */
  3. /* (C) Copyright 1995 by Carnegie Mellon University
  4.  * All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software
  7.  * and its documentation for any purpose is hereby granted without
  8.  * fee, provided that the above copyright notice appear in all copies
  9.  * and that both that copyright notice and this permission notice
  10.  * appear in supporting documentation, and that the name of Carnegie
  11.  * Mellon University not be used in advertising or publicity
  12.  * pertaining to distribution of the software without specific,
  13.  * written prior permission.  Carnegie Mellon University makes no
  14.  * representations about the suitability of this software for any
  15.  * purpose.  It is provided "as is" without express or implied
  16.  * warranty.
  17.  *
  18.  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
  19.  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  20.  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
  21.  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  22.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  23.  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  24.  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  25.  * SOFTWARE.
  26.  */
  27. /* (C) Copyright 1994-1995 by Christopher J. Newman
  28.  * All Rights Reserved.
  29.  *
  30.  * Permission to use, copy, modify, distribute, and sell this software and its
  31.  * documentation for any purpose is hereby granted without fee, provided that
  32.  * the above copyright notice appear in all copies and that both that
  33.  * copyright notice and this permission notice appear in supporting
  34.  * documentation, and that the name of Christopher J. Newman not be used in
  35.  * advertising or publicity pertaining to distribution of the software without
  36.  * specific, written prior permission.  Christopher J. Newman makes no
  37.  * representations about the suitability of this software for any purpose.  It
  38.  * is provided "as is" without express or implied warranty.
  39.  *
  40.  * CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  41.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
  42.  * SHALL CHRISTOPHER J. NEWMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  43.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  44.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  45.  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  46.  * OF THIS SOFTWARE.
  47.  */
  48.  
  49. #include <stdio.h>
  50. #include <string.h>
  51. #include "macmpack.h"   /* for copy_buf & watch */
  52.  
  53. /* applefile definitions used */
  54. #define APPLESINGLE_MAGIC 0x00051600L
  55. #define APPLEDOUBLE_MAGIC 0x00051607L
  56. #define VERSION 0x00020000
  57. #define ENT_DFORK   1
  58. #define ENT_RFORK   2
  59. #define ENT_NAME    3
  60. #define ENT_COMMENT 4
  61. #define ENT_DATES   8
  62. #define ENT_FINFO   9
  63. #define CONVERT_TIME 1265437696L
  64.  
  65. /* applefile structures */
  66. typedef struct ap_header {
  67.     long magic;
  68.     long version;
  69.     char fill[16];
  70.     short entries;
  71. } ap_header;
  72. typedef struct ap_entry {
  73.     unsigned long id;
  74.     unsigned long offset;
  75.     unsigned long length;
  76. } ap_entry;
  77. typedef struct ap_dates {
  78.     long create, modify, backup, access;
  79. } ap_dates;
  80.  
  81. /* default number of entries */
  82. #define NUM_ENTRIES 6
  83.  
  84. /* Generate an applefile
  85.  *  outfile -- output file
  86.  *  fpb -- hierarchical file parameter block
  87.  *  rfork, dfork -- resource & data forks
  88.  * returns -1 on failure, 0 on success
  89.  *
  90.  * closes dfork & rfork, but not outputfile
  91.  */
  92. int encode_applefile(FILE *outfile, HFileInfo *fpb, FILE *rfork, FILE *dfork)
  93. {
  94.     ap_header head;
  95.     ap_entry entries[NUM_ENTRIES];
  96.     ap_dates dates;
  97.     short i, count;
  98.     long comlen, procID;
  99.     DateTimeRec cur_time;
  100.     unsigned long cur_secs;
  101.     IOParam vinfo;
  102.     GetVolParmsInfoBuffer vp;
  103.     DTPBRec dtp;
  104.     char comment[256];
  105.     
  106.     /* make sure things look OK */
  107.     if (!rfork || !outfile) {
  108.         if (rfork) fclose(rfork);
  109.         if (dfork) fclose(dfork);
  110.         if (outfile) fclose(outfile);
  111.         return (-1);
  112.     }
  113.     
  114.     /* get a file comment, if possible */
  115.     procID = 0;
  116.     GetWDInfo(fpb->ioVRefNum, &fpb->ioVRefNum, &fpb->ioDirID, &procID);
  117.     memset((void *) &vinfo, '\0', sizeof (vinfo));
  118.     vinfo.ioVRefNum = fpb->ioVRefNum;
  119.     vinfo.ioBuffer = (Ptr) &vp;
  120.     vinfo.ioReqCount = sizeof (vp);
  121.     comlen = 0;
  122.     if (PBHGetVolParmsSync((HParmBlkPtr) &vinfo) == noErr &&
  123.         ((vp.vMAttrib >> bHasDesktopMgr) & 1)) {
  124.         memset((void *) &dtp, '\0', sizeof (dtp));
  125.         dtp.ioVRefNum = fpb->ioVRefNum;
  126.         if (PBDTGetPath(&dtp) == noErr) {
  127.             dtp.ioDTBuffer = (Ptr) comment;
  128.             dtp.ioNamePtr = fpb->ioNamePtr;
  129.             dtp.ioDirID = fpb->ioFlParID;
  130.             if (PBDTGetCommentSync(&dtp) == noErr) comlen = dtp.ioDTActCount;
  131.         }
  132.     }
  133.     
  134.     /* write header */
  135.     head.magic = dfork ? APPLESINGLE_MAGIC : APPLEDOUBLE_MAGIC;
  136.     head.version = VERSION;
  137.     memset(head.fill, '\0', sizeof (head.fill));
  138.     head.entries = NUM_ENTRIES - (dfork ? 0 : 1);
  139.     fwrite((char *) &head, sizeof (head), 1, outfile);
  140.     
  141.     /* write entry descriptors */
  142.     entries[0].offset = sizeof (head) + sizeof (ap_entry) * head.entries;
  143.     entries[0].id = ENT_NAME;
  144.     entries[0].length = *fpb->ioNamePtr;
  145.     entries[1].id = ENT_FINFO;
  146.     entries[1].length = sizeof (FInfo) + sizeof (FXInfo);
  147.     entries[2].id = ENT_DATES;
  148.     entries[2].length = sizeof (ap_dates);
  149.     entries[3].id = ENT_COMMENT;
  150.     entries[3].length = comlen;
  151.     entries[4].id = ENT_RFORK;
  152.     entries[4].length = fpb->ioFlRLgLen;
  153.     entries[5].id = ENT_DFORK;
  154.     entries[5].length = fpb->ioFlLgLen;
  155.     for (i = 1; i < NUM_ENTRIES; ++i) {
  156.         entries[i].offset = entries[i-1].offset + entries[i-1].length;
  157.     }
  158.     fwrite((char *) entries, sizeof (ap_entry), head.entries, outfile);
  159.     
  160.     /* write name */
  161.     fwrite((char *) fpb->ioNamePtr + 1, *fpb->ioNamePtr, 1, outfile);
  162.     /* write finder info */
  163.     fwrite((char *) &fpb->ioFlFndrInfo, sizeof (FInfo), 1, outfile);
  164.     fwrite((char *) &fpb->ioFlXFndrInfo, sizeof (FXInfo), 1, outfile);
  165.     /* write dates */
  166.     GetTime(&cur_time);
  167.     Date2Secs(&cur_time, &cur_secs);
  168.     dates.create = fpb->ioFlCrDat + CONVERT_TIME;
  169.     dates.modify = fpb->ioFlMdDat + CONVERT_TIME;
  170.     dates.backup = fpb->ioFlBkDat + CONVERT_TIME;
  171.     dates.access = cur_secs + CONVERT_TIME;
  172.     fwrite((char *) &dates, sizeof (ap_dates), 1, outfile);
  173.     /* write comment */
  174.     if (comlen) fwrite(comment, sizeof (char), comlen, outfile);
  175.     /* write resource fork */
  176.     while ((count = fread(copy_buf, sizeof (char), sizeof (copy_buf), rfork)) > 0) {
  177.         fwrite(copy_buf, sizeof (char), count, outfile);
  178.     }
  179.     fclose(rfork);
  180.     /* write data fork */
  181.     if (dfork) {
  182.         while ((count = fread(copy_buf, sizeof (char), sizeof (copy_buf), dfork)) > 0) {
  183.             fwrite(copy_buf, sizeof (char), count, outfile);
  184.         }
  185.         fclose(dfork);
  186.     }
  187.     
  188.     return (0);
  189. }
  190.  
  191. /* decode an applefile
  192.  *  infile -- input file
  193.  *  fspec  -- file spec of saved file
  194.  * returns -1 on failure, 0 on success
  195.  */
  196. int decode_applefile(FILE *infile, FSSpec *fspec)
  197. {
  198.     ap_header head;
  199.     ap_entry entries[NUM_ENTRIES + 1];
  200.     ap_dates dates;
  201.     StandardFileReply reply;
  202.     int i, j;
  203.     short refnum;
  204.     long count;
  205.     OSErr err;
  206.     HFileInfo *fpb;
  207.     CInfoPBRec cipbr;
  208.     long procID;
  209.     IOParam vinfo;
  210.     GetVolParmsInfoBuffer vp;
  211.     DTPBRec dtp;
  212.     char comment[256];
  213.     
  214.     /* read & verify header */
  215.     fread((char *) &head, sizeof (head), 1, infile);
  216.     if (head.magic != APPLESINGLE_MAGIC && head.magic != APPLEDOUBLE_MAGIC) {
  217.         return (-1);
  218.     }
  219.     if (head.version != VERSION) {
  220.         return (-1);
  221.     }
  222.     
  223.     /* read entries */
  224.     for (i = j = 0; i < head.entries; ++i) {
  225.         fread((char *) (entries + j), sizeof (ap_entry), 1, infile);
  226.         if (j < NUM_ENTRIES) switch (entries[j].id) {
  227.             case ENT_NAME:
  228.             case ENT_FINFO:
  229.             case ENT_DATES:
  230.             case ENT_COMMENT:
  231.             case ENT_RFORK:
  232.             case ENT_DFORK:
  233.                 ++j;
  234.                 break;
  235.         }
  236.     }
  237.     
  238.     /* read name */
  239.     for (i = 0; i < j && entries[i].id != ENT_NAME; ++i);
  240.     if (i == j) return (-1);
  241.     fseek(infile, entries[i].offset, SEEK_SET);
  242.     if (entries[i].length > 63) entries[i].length = 63;
  243.     *fspec->name = fread((char *) fspec->name + 1, sizeof (char), entries[i].length, infile);
  244.     SetCursor(&arrow);
  245.     NAputFile("\pSave decoded file as:", fspec->name, &reply);
  246.     SetCursor(&watch);
  247.     statrefresh();
  248.     if (!reply.sfGood) return (didchat = -1);
  249.     *fspec = reply.sfFile;
  250.  
  251.     /* create & get info for file */
  252.     if (reply.sfReplacing) HDelete(fspec->vRefNum, fspec->parID, fspec->name);
  253.     if (HCreate(fspec->vRefNum, fspec->parID, fspec->name, '????', '????') != noErr) {
  254.         return (-1);
  255.     }
  256.     fpb = (HFileInfo *) &cipbr;
  257.     fpb->ioVRefNum = fspec->vRefNum;
  258.     fpb->ioNamePtr = fspec->name;
  259.     fpb->ioDirID = fspec->parID;
  260.     fpb->ioFDirIndex = 0;
  261.     PBGetCatInfoSync(&cipbr);
  262.     
  263.     /* get finder info */
  264.     for (i = 0; i < j && entries[i].id != ENT_FINFO; ++i);
  265.     if (i < j) {
  266.         fseek(infile, entries[i].offset, SEEK_SET);
  267.         fread((char *) &fpb->ioFlFndrInfo, sizeof (FInfo), 1, infile);
  268.         fread((char *) &fpb->ioFlXFndrInfo, sizeof (FXInfo), 1, infile);
  269.         fpb->ioFlFndrInfo.fdFlags &= 0xf800; /* clear flags maintained by finder */
  270.     }
  271.     
  272.     /* get file date info */
  273.     for (i = 0; i < j && entries[i].id != ENT_DATES; ++i);
  274.     if (i < j) {
  275.         fseek(infile, entries[i].offset, SEEK_SET);
  276.         fread((char *) &dates, sizeof (dates), 1, infile);
  277.         fpb->ioFlCrDat = dates.create - CONVERT_TIME;
  278.         fpb->ioFlMdDat = dates.modify - CONVERT_TIME;
  279.         fpb->ioFlBkDat = dates.backup - CONVERT_TIME;
  280.     }
  281.     
  282.     /* update info */
  283.     fpb->ioDirID = fpb->ioFlParID;
  284.     PBSetCatInfoSync(&cipbr);
  285.     
  286.     /* get comment & save it */
  287.     for (i = 0; i < j && entries[i].id != ENT_COMMENT; ++i);
  288.     if (i < j && entries[i].length != 0) {
  289.         memset((void *) &vinfo, '\0', sizeof (vinfo));
  290.         vinfo.ioVRefNum = fpb->ioVRefNum;
  291.         vinfo.ioBuffer = (Ptr) &vp;
  292.         vinfo.ioReqCount = sizeof (vp);
  293.         if (PBHGetVolParmsSync((HParmBlkPtr) &vinfo) == noErr &&
  294.             ((vp.vMAttrib >> bHasDesktopMgr) & 1)) {
  295.             memset((void *) &dtp, '\0', sizeof (dtp));
  296.             dtp.ioVRefNum = fpb->ioVRefNum;
  297.             if (PBDTGetPath(&dtp) == noErr) {
  298.                 if (entries[i].length > 255) entries[i].length = 255;
  299.                 fseek(infile, entries[i].offset, SEEK_SET);
  300.                 fread(comment, entries[i].length, 1, infile);
  301.                 dtp.ioDTBuffer = (Ptr) comment;
  302.                 dtp.ioNamePtr = fpb->ioNamePtr;
  303.                 dtp.ioDirID = fpb->ioDirID;
  304.                 dtp.ioDTReqCount = entries[i].length;
  305.                 if (PBDTSetCommentSync(&dtp) == noErr) {
  306.                     PBDTFlushSync(&dtp);
  307.                 }
  308.             }
  309.         }
  310.     }
  311.     
  312.     /* do resource/data forks */
  313.     for (i = 0; i < j; ++i) {
  314.         if (entries[i].id == ENT_RFORK || entries[i].id == ENT_DFORK) {
  315.             fseek(infile, entries[i].offset, SEEK_SET);
  316.             if (entries[i].id == ENT_DFORK) {
  317.                 err = HOpen(fspec->vRefNum, fspec->parID, fspec->name, 2, &refnum);
  318.             } else {
  319.                 err = HOpenRF(fspec->vRefNum, fspec->parID, fspec->name, 2, &refnum);
  320.             }
  321.             if (err != noErr) {
  322.                 HDelete(fspec->vRefNum, fspec->parID, fspec->name);
  323.                 return (-1);
  324.             }
  325.             while (entries[i].length > sizeof (copy_buf)) {
  326.                 count = fread(copy_buf, sizeof (char), sizeof (copy_buf), infile);
  327.                 entries[i].length -= count;
  328.                 FSWrite(refnum, &count, (Ptr) copy_buf);
  329.             }
  330.             count = fread(copy_buf, sizeof (char), entries[i].length, infile);
  331.             FSWrite(refnum, &count, (Ptr) copy_buf);
  332.             FSClose(refnum);
  333.         }
  334.     }
  335.     
  336.     return (0);
  337. }
  338.