"Fossies" - the Fresh Open Source Software Archive

Member "epstool-3.08/src/cmac.c" (10 Jun 2005, 28408 Bytes) of package /linux/misc/old/ghost/ghostgum/epstool-3.08-os2.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* Copyright (C) 2003-2005 Ghostgum Software Pty Ltd.  All rights reserved.
    2 
    3   This software is provided AS-IS with no warranty, either express or
    4   implied.
    5 
    6   This software is distributed under licence and may not be copied,
    7   modified or distributed except as expressly authorised under the terms
    8   of the licence contained in the file LICENCE in this distribution.
    9 
   10   For more information about licensing, please refer to
   11   http://www.ghostgum.com.au/ or contact Ghostsgum Software Pty Ltd, 
   12   218 Gallaghers Rd, Glen Waverley VIC 3150, AUSTRALIA, 
   13   Fax +61 3 9886 6616.
   14 */
   15 
   16 /* $Id: cmac.c,v 1.11 2005/06/10 09:39:24 ghostgum Exp $ */
   17 /* Macintosh AppleSingle, AppleDouble and MacBinary file formats */
   18 /* Macintosh does not use a flat file system.
   19  * Each file can have a data fork and a resource fork.
   20  * EPSF files have the PostScript in the data fork, 
   21  * optionally have a PICT preview in the resource fork.
   22  * In addition, finder info gives the file type using FOURCC codes
   23  * such as "EPSF" or "PICT".
   24  * When files are copied to foreign file systems, the resource
   25  * fork may be left behind.  Alternatives to retain the resource
   26  * fork are to package the finder data, data fork and resource fork 
   27  * in a single MacBinary or AppleSingle file, 
   28  * or to put the data fork in a flat file and the finder info 
   29  * and resource fork in an AppleDouble file.
   30  */
   31 
   32 #include "common.h"
   33 #include <time.h>
   34 #include "cmac.h"
   35 
   36 static int extract_mac_data(GFile *f, LPCTSTR outname, 
   37    unsigned long begin, unsigned long length, unsigned long header);
   38 
   39 DWORD
   40 get_bigendian_dword(const unsigned char *buf)
   41 {
   42     DWORD dw;
   43     dw = ((DWORD)buf[0])<<24;
   44     dw += ((DWORD)buf[1])<<16;
   45     dw += ((DWORD)buf[2])<<8;
   46     dw += (DWORD)buf[3];
   47     return dw;
   48 }
   49 
   50 WORD
   51 get_bigendian_word(const unsigned char *buf)
   52 {
   53     WORD w;
   54     w = (WORD)(buf[0]<<8);
   55     w |= (WORD)buf[1];
   56     return w;
   57 }
   58 
   59 /* write DWORD as DWORD */
   60 void
   61 put_bigendian_dword(unsigned char *dw, DWORD val)
   62 {
   63     dw[0] = (unsigned char)((val>>24) & 0xff);
   64     dw[1] = (unsigned char)((val>>16) & 0xff);
   65     dw[2] = (unsigned char)((val>>8)  & 0xff);
   66     dw[3] = (unsigned char)( val      & 0xff);
   67 }
   68 
   69 
   70 /* write WORD as WORD */
   71 void
   72 put_bigendian_word(unsigned char *w, WORD val)
   73 {
   74     w[0] = (unsigned char)((val>>8)  & 0xff);
   75     w[1] = (unsigned char)( val      & 0xff);
   76 }
   77 
   78 const unsigned char apple_single_magic[4] = {0x00, 0x05, 0x16, 0x00};
   79 const unsigned char apple_double_magic[4] = {0x00, 0x05, 0x16, 0x07};
   80 
   81 CMACFILE *get_mactype(GFile *f)
   82 {
   83 #define ASD_HEADER_LENGTH 26
   84 #define MACBIN_HEADER_LENGTH 128
   85     unsigned char data[MACBIN_HEADER_LENGTH];
   86     CMAC_TYPE type = CMAC_TYPE_NONE;
   87     CMACFILE *mac;
   88     int i;
   89     int asd_entries = 0;
   90     DWORD version;
   91     DWORD EntryID;
   92     DWORD Offset;
   93     DWORD Length;
   94     FILE_POS file_length;
   95     int count;
   96 
   97     if (f == NULL)
   98     return NULL;
   99     file_length = gfile_get_length(f);
  100     count = gfile_read(f, data, ASD_HEADER_LENGTH);
  101     if (count >= ASD_HEADER_LENGTH) {
  102     if (memcmp(data, apple_single_magic, 4) == 0)
  103         type = CMAC_TYPE_SINGLE;
  104     else if (memcmp(data, apple_double_magic, 4) == 0)
  105         type = CMAC_TYPE_DOUBLE;
  106     if ((type == CMAC_TYPE_SINGLE || type == CMAC_TYPE_DOUBLE)) {
  107         version = get_bigendian_dword(data+4);
  108         if ((version != 0x00010000) && (version != 0x00020000))
  109         type = CMAC_TYPE_NONE;
  110         asd_entries = get_bigendian_word(data+24);
  111     }
  112     else if (type == CMAC_TYPE_NONE) {
  113         count += gfile_read(f, data+ASD_HEADER_LENGTH, 
  114         MACBIN_HEADER_LENGTH-ASD_HEADER_LENGTH);
  115         if (count >= MACBIN_HEADER_LENGTH && 
  116         (data[0]==0x0) && 
  117         (data[1] >= 1) && (data[1] <= 63) && 
  118         (data[74]==0x0) && (data[82]==0x0) &&
  119         (data[65]>=' ') && (data[65]<='z') &&
  120         (data[66]>=' ') && (data[66]<='z') &&
  121         (data[67]>=' ') && (data[67]<='z') &&
  122         (data[68]>=' ') && (data[68]<='z') &&
  123         (data[69]>=' ') && (data[69]<='z') &&
  124         (data[70]>=' ') && (data[70]<='z') &&
  125         (data[71]>=' ') && (data[71]<='z') &&
  126         (data[72]>=' ') && (data[72]<='z')) {
  127         type = CMAC_TYPE_MACBIN;
  128         }
  129         else {
  130         /* check for bare resource fork */
  131         DWORD data_begin = get_bigendian_dword(data);
  132         DWORD map_begin = get_bigendian_dword(data+4);
  133         DWORD data_length = get_bigendian_dword(data+8);
  134         DWORD map_length = get_bigendian_dword(data+12);
  135         if ((data_begin == 0x100) && 
  136             (data_begin + data_length == map_begin) &&
  137             (map_begin + map_length == file_length))
  138             type = CMAC_TYPE_RSRC;
  139         }
  140     }
  141     }
  142 
  143     if (type == CMAC_TYPE_NONE)
  144     return NULL;
  145 
  146     mac = (CMACFILE *)malloc(sizeof(CMACFILE));
  147     if (mac == NULL)
  148     return NULL;
  149     memset(mac, 0, sizeof(CMACFILE));
  150     mac->type = type;
  151 
  152     /* Read Mac Binary stuff */
  153     if (type == CMAC_TYPE_MACBIN) {
  154     memcpy(mac->file_type, data+65, 4);
  155     memcpy(mac->file_creator, data+69, 4);
  156     mac->data_begin = 128;
  157     mac->data_length = get_bigendian_dword(data+83);
  158         mac->resource_begin = 
  159         (mac->data_begin + mac->data_length + 127 ) & ~127;
  160     mac->resource_length = get_bigendian_dword(data+87);
  161     }
  162     else if (type == CMAC_TYPE_RSRC) {
  163     memcpy(mac->file_type, "    ", 4);
  164     memcpy(mac->file_creator, "    ", 4);
  165     mac->resource_begin = 0;
  166     mac->resource_length = file_length;
  167     }
  168     else {
  169     /* AppleSingle or AppleDouble */
  170     for (i=0; i<asd_entries; i++) {
  171         count = gfile_read(f, data, 12);
  172         EntryID = get_bigendian_dword(data);
  173         Offset = get_bigendian_dword(data+4);
  174         Length = get_bigendian_dword(data+8);
  175         switch (EntryID) {
  176         case 1: /* Data fork */
  177             mac->data_begin = Offset;
  178             mac->data_length = Length;
  179             break;
  180         case 2: /* Resource fork */
  181             mac->resource_begin = Offset;
  182             mac->resource_length = Length;
  183             break;
  184         case 9: /* Finder info */
  185             mac->finder_begin = Offset;
  186             mac->finder_length = Length;
  187             break;
  188         }
  189     }
  190     if (mac->finder_begin != 0) {
  191         gfile_seek(f, mac->finder_begin, SEEK_SET);
  192         count = gfile_read(f, data, min(sizeof(data), mac->finder_length));
  193         if (count >= 8) {
  194         memcpy(mac->file_type, data, 4);
  195         memcpy(mac->file_creator, data+4, 4);
  196         }
  197     }
  198     }
  199 
  200     return mac;
  201 }
  202 
  203 
  204 typedef struct CMAC_RESOURCE_HEADER_s {
  205     DWORD data_begin;
  206     DWORD map_begin;
  207     DWORD data_length;
  208     DWORD map_length;
  209 } CMAC_RESOURCE_HEADER;
  210 
  211 typedef struct CMAC_RESOURCE_MAP_s {
  212     unsigned char reshdr[16];
  213     DWORD reshdl;
  214     WORD filerefno;
  215     WORD attributes;
  216     WORD offset_type_list;
  217     WORD offset_name_list;
  218     WORD type_count;
  219 } CMAC_RESOURCE_MAP;
  220 
  221 typedef struct CMAC_RESOURCE_TYPE_LIST_s {
  222     unsigned char type[4];
  223     WORD count;
  224     WORD offset_ref_list;
  225 } CMAC_RESOURCE_TYPE_LIST;
  226 
  227 typedef struct CMAC_RESOURCE_REF_LIST_s {
  228     WORD id;
  229     WORD offset_name;
  230     unsigned char attributes;
  231     DWORD offset_data;  /* 3 bytes only */
  232     DWORD handle;
  233 } CMAC_RESOURCE_REF_LIST;
  234 
  235 
  236 /* Find the location of PICT in the resource fork, if present */
  237 int
  238 get_pict(GFile *f, CMACFILE *mac, int debug)
  239 {
  240     CMAC_RESOURCE_HEADER reshdr;
  241     CMAC_RESOURCE_MAP resmap;
  242     CMAC_RESOURCE_TYPE_LIST typelist;
  243     CMAC_RESOURCE_REF_LIST reflist;
  244     DWORD res_offset;
  245     DWORD map_offset;
  246     DWORD type_offset;
  247     DWORD ref_offset;
  248     DWORD preview_offset = 0;
  249     DWORD preview_length = 0;
  250     unsigned char data[16];
  251     char name[257];
  252     int name_length;
  253     int count;
  254     int i, j;
  255     if (mac == NULL)
  256     return 1;
  257     if (mac->type == CMAC_TYPE_NONE)
  258     return 1;
  259     if (((mac->type != CMAC_TYPE_RSRC) && (mac->resource_begin == 0)) 
  260     || (mac->resource_length == 0))
  261     return 1;
  262 
  263     memset(&resmap, 0, sizeof(resmap));
  264     memset(&typelist, 0, sizeof(typelist));
  265     memset(&reflist, 0, sizeof(reflist));
  266 
  267     res_offset = mac->resource_begin;
  268     gfile_seek(f, res_offset, SEEK_SET);
  269     count = gfile_read(f, data, 16);
  270     if (count != 16)
  271     return -1;
  272     reshdr.data_begin = get_bigendian_dword(data);
  273     reshdr.map_begin = get_bigendian_dword(data+4);
  274     reshdr.data_length = get_bigendian_dword(data+8);
  275     reshdr.map_length = get_bigendian_dword(data+12);
  276     if (debug) {
  277     fprintf(stdout, "resource data: %ld %ld\n", 
  278         reshdr.data_begin, reshdr.data_length);
  279     fprintf(stdout, "resource map: %ld %ld\n", 
  280         reshdr.map_begin, reshdr.map_length);
  281     }
  282 
  283     map_offset = res_offset+reshdr.map_begin;
  284     gfile_seek(f, map_offset, SEEK_SET);
  285     count = gfile_read(f, &resmap.reshdr, 16);
  286     if (count != 16)
  287     return -1;
  288     count = gfile_read(f, data, 14);
  289     if (count != 14)
  290     return -1;
  291     resmap.reshdl = get_bigendian_dword(data);
  292     resmap.filerefno = get_bigendian_word(data+4);
  293     resmap.attributes = get_bigendian_word(data+6);
  294     resmap.offset_type_list = get_bigendian_word(data+8);
  295     resmap.offset_name_list = get_bigendian_word(data+10);
  296     resmap.type_count = get_bigendian_word(data+12);
  297 
  298     if (debug) {
  299     fprintf(stdout, " resource handle %ld\n", resmap.reshdl);
  300     fprintf(stdout, " file reference number %d\n", 
  301         resmap.filerefno);
  302     fprintf(stdout, " attributes 0x%x\n", resmap.attributes);
  303     fprintf(stdout, " offset type list %d\n", resmap.offset_type_list);
  304     fprintf(stdout, " offset name list %d\n", resmap.offset_name_list);
  305     fprintf(stdout, " type count %d\n", resmap.type_count);
  306     }
  307 
  308     /* Documentation says that the type list starts at 
  309      * map_offset + resmap.offset_type_list, but we have
  310      * found that it is actually 2 bytes further on.
  311      * Perhaps the type count is supposed be part of the type_list
  312      */
  313     type_offset = map_offset+resmap.offset_type_list;
  314     for (i=0; i<=resmap.type_count; i++) {
  315         gfile_seek(f, type_offset + 2 + i * 8, SEEK_SET); /* +2 KLUDGE */
  316         count = gfile_read(f, &typelist.type, 4);
  317     if (count != 4)
  318         return -1;
  319         count = gfile_read(f, data, 4);
  320     if (count != 4)
  321         return -1;
  322     typelist.count = get_bigendian_word(data);
  323     typelist.offset_ref_list = get_bigendian_word(data+2);
  324     if (debug)
  325         fprintf(stdout, "type %d %c%c%c%c count=%d offset=%d\n", i,
  326         typelist.type[0], typelist.type[1], 
  327         typelist.type[2], typelist.type[3],
  328         typelist.count, typelist.offset_ref_list);
  329     ref_offset = type_offset + typelist.offset_ref_list;
  330     for (j=0; j<=typelist.count; j++) {
  331             gfile_seek(f, ref_offset + j * 12, SEEK_SET);
  332         count = gfile_read(f, data, 12);
  333         if (count != 12)
  334         return -1;
  335         reflist.id = get_bigendian_word(data);
  336         reflist.offset_name = get_bigendian_word(data+2);
  337         reflist.attributes = data[4];
  338         reflist.offset_data = ((DWORD)data[5])<<16;
  339         reflist.offset_data += ((DWORD)data[6])<<8;
  340         reflist.offset_data += ((DWORD)data[7]);
  341         reflist.handle = get_bigendian_dword(data+8);
  342         if (debug) {
  343         fprintf(stdout, "  reflist %d id=%d name=%d attributes=0x%x data=%ld 0x%lx\n", 
  344             j, reflist.id, reflist.offset_name, reflist.attributes,
  345             reflist.offset_data, reflist.offset_data);
  346         gfile_seek(f, res_offset + reshdr.data_begin +
  347             reflist.offset_data, SEEK_SET);
  348         count = gfile_read(f, data, 4);
  349         if (count != 4)
  350             return -1;
  351         fprintf(stdout, "  length=%ld 0x%lx\n",
  352         get_bigendian_dword(data), get_bigendian_dword(data));
  353         }
  354 
  355 
  356         if ((resmap.offset_name_list < reshdr.map_length) &&
  357         (resmap.offset_name_list != 0xffff) &&
  358         (reflist.offset_name != 0xffff)) {
  359         gfile_seek(f, map_offset + resmap.offset_name_list + 
  360             reflist.offset_name, SEEK_SET);
  361         count = gfile_read(f, data, 1);
  362         if (count != 1)
  363             return -1;
  364         name_length = data[0];
  365         if (name_length <= 256) {
  366             count = gfile_read(f, name, name_length);
  367             if (count != name_length)
  368             return -1;
  369             name[name_length] = '\0';
  370             if (debug)
  371             fprintf(stdout, "    name=%s\n", name);
  372         }
  373         }
  374         if ((memcmp(typelist.type, "PICT", 4) == 0) &&
  375         (reflist.id == 256)) {
  376         /* This is the PICT preview for an EPS files */
  377         preview_offset = 
  378             res_offset + reshdr.data_begin + reflist.offset_data;
  379         }
  380     }
  381     }
  382 
  383     if (preview_offset != 0) {
  384     gfile_seek(f, preview_offset, SEEK_SET);
  385     gfile_read(f, data, 4);
  386     preview_length = get_bigendian_dword(data);
  387     if (preview_length != 0) {
  388         mac->pict_begin = preview_offset + 4;
  389         mac->pict_length = preview_length;
  390     }
  391     }
  392     return 0;
  393 }
  394 
  395 
  396 /* Extract EPSF from data resource fork to a file */
  397 /* Returns 0 on success, negative on failure */
  398 static int 
  399 extract_mac_data(GFile *f, LPCTSTR outname, 
  400    unsigned long begin, unsigned long length, unsigned long header)
  401 {
  402 unsigned long len;
  403 unsigned int count;
  404 char *buffer;
  405 GFile *outfile;
  406 int code = 0;
  407     if ((begin == 0) || (length == 0))
  408     return -1;
  409 
  410     if (*outname == '\0')
  411     return -1;
  412 
  413     /* create buffer for file copy */
  414     buffer = (char *)malloc(COPY_BUF_SIZE);
  415     if (buffer == (char *)NULL)
  416     return -1;
  417 
  418     outfile = gfile_open(outname, gfile_modeWrite | gfile_modeCreate);
  419     if (outfile == (GFile *)NULL) {
  420     free(buffer);
  421     return -1;
  422     }
  423 
  424     /* PICT files when stored separately start with 512 nulls */
  425     memset(buffer, 0, COPY_BUF_SIZE);
  426     if (header && header < COPY_BUF_SIZE)
  427         gfile_write(outfile, buffer, header);
  428 
  429     gfile_seek(f, begin, gfile_begin); /* seek to EPSF or PICT */
  430     len = length; 
  431     while ( (count = (unsigned int)min(len,COPY_BUF_SIZE)) != 0 ) {
  432     count = (int)gfile_read(f, buffer, count);
  433     gfile_write(outfile, buffer, count);
  434     if (count == 0) {
  435         len = 0;
  436         code = -1;
  437     }
  438     else
  439         len -= count;
  440     }
  441     free(buffer);
  442     gfile_close(outfile);
  443 
  444     return code;
  445 }
  446 
  447 /* Extract PICT from resource fork to a file */
  448 /* Returns 0 on success, negative on failure */
  449 int 
  450 extract_mac_pict(GFile *f, CMACFILE *mac, LPCTSTR outname)
  451 {
  452     if ((f == NULL) || (mac == NULL))
  453     return -1;
  454     /* PICT files when stored separately start with 512 nulls */
  455     return extract_mac_data(f, outname, 
  456     mac->pict_begin, mac->pict_length, 512);
  457 }
  458 
  459 /* Extract EPSF from data fork to a file */
  460 /* Returns 0 on success, negative on failure */
  461 int 
  462 extract_mac_epsf(GFile *f, CMACFILE *mac, LPCTSTR outname)
  463 {
  464     if ((f == NULL) || (mac == NULL))
  465     return -1;
  466     return extract_mac_data(f, outname, 
  467     mac->data_begin, mac->data_length, 0);
  468 }
  469 
  470 /* Write resources containing a single PICT with id=256 to file.
  471  * Return number of bytes written if OK, -ve if not OK.
  472  * If f==NULL, return number of bytes required for resources.
  473  */
  474 int
  475 write_resource_pict(GFile *f, LPCTSTR pictname)
  476 {
  477     GFile *pictfile;
  478     unsigned long pict_length;
  479     unsigned char data[256];
  480     unsigned long data_offset = 256;
  481     unsigned long map_length = 58;
  482     unsigned long pict_offset = 0;  /* at start of resource data */
  483     unsigned resource_length;
  484     unsigned long len;
  485     unsigned int count;
  486     int code = 0;
  487 
  488     pictfile = gfile_open(pictname, gfile_modeRead);
  489     if (pictfile == NULL)
  490     return -1;
  491     pict_length = gfile_get_length(pictfile) - 512;
  492     if ((long)pict_length < 0) {
  493     gfile_close(pictfile);
  494     return -1;
  495     }
  496     resource_length = data_offset + 4 + pict_length + map_length;
  497     if (f == NULL) {
  498     gfile_close(pictfile);
  499     return resource_length;
  500     }
  501 
  502     /* resource header */
  503     memset(data, 0, sizeof(data));
  504     put_bigendian_dword(data, data_offset); /* data offset */
  505     put_bigendian_dword(data+4, data_offset + 4 + pict_length); /* map offset */
  506     put_bigendian_dword(data+8, pict_length + 4); /* data length */
  507     put_bigendian_dword(data+12, map_length);   /* map length */
  508     gfile_write(f, data, data_offset);
  509 
  510     /* pict file */
  511     put_bigendian_dword(data, pict_length);
  512     gfile_write(f, data, 4);
  513     len = pict_length; 
  514     gfile_seek(pictfile, 512, SEEK_SET);
  515     while ( (count = (unsigned int)min(len,sizeof(data))) != 0 ) {
  516     count = (int)gfile_read(pictfile, data, count);
  517     gfile_write(f, data, count);
  518     if (count == 0) {
  519         len = 0;
  520         code = -1;
  521     }
  522     else
  523         len -= count;
  524     }
  525     gfile_close(pictfile);
  526     if (code < 0)
  527     return code;
  528 
  529     /* resource map */
  530     memset(data, 0, sizeof(data));
  531     put_bigendian_dword(data+16, 0);    /* resource handle */
  532     put_bigendian_word(data+20, 0); /* file reference number */
  533     put_bigendian_word(data+22, 0); /* attributes */
  534     put_bigendian_word(data+24, 28);    /* offset to type list */
  535     put_bigendian_word(data+26, 50);    /* offset to name list */
  536     gfile_write(f, data, 28);
  537 
  538     /* type list */
  539     memset(data, 0, sizeof(data));
  540     put_bigendian_word(data, 0);    /* number of types */
  541     memcpy(data+2, "PICT", 4);
  542     put_bigendian_word(data+6, 0);  /* type count */
  543     put_bigendian_word(data+8, 10); /* offset to ref list */
  544     gfile_write(f, data, 10);
  545 
  546     /* reference list */
  547     memset(data, 0, sizeof(data));
  548     put_bigendian_word(data, 256);  /* resource id for EPSF preview */
  549     put_bigendian_word(data+2, 0);  /* offset to name */
  550     data[4] = '\0';         /* attributes */
  551     data[5] = (unsigned char)((pict_offset>>16) & 0xff);
  552     data[6] = (unsigned char)((pict_offset>>8)  & 0xff);
  553     data[7] = (unsigned char)( pict_offset      & 0xff);
  554     put_bigendian_dword(data+8, 0); /* handle */
  555     gfile_write(f, data, 12);
  556 
  557     /* name list */
  558     memset(data, 0, sizeof(data));
  559     data[0] = 7;
  560     memcpy(data+1, "Preview", 7);
  561     gfile_write(f, data, 8);
  562 
  563     return resource_length;
  564 }
  565 
  566 /* Write an AppleDouble file containing a single PICT with id=256 to file. */
  567 int
  568 write_appledouble(GFile *f, LPCTSTR pictname)
  569 {
  570     unsigned char data[256];
  571     unsigned long resource_length;
  572 
  573     /* get length of resources */
  574     resource_length = write_resource_pict(NULL, pictname);
  575 
  576     memset(data, 0, sizeof(data));
  577     memcpy(data, apple_double_magic, 4);    /* magic signature */
  578     put_bigendian_dword(data+4, 0x00020000);    /* version */
  579     /* 16 bytes filler */
  580     put_bigendian_word(data+24, 2); /* 2 entries, finder and resource */
  581     /* finder descriptor */
  582     put_bigendian_dword(data+26, 9);    /* finder id */
  583     put_bigendian_dword(data+30, 50);   /* offset */
  584     put_bigendian_dword(data+34, 32);   /* length */
  585     /* resource descriptor */
  586     put_bigendian_dword(data+38, 2);    /* resource fork id */
  587     put_bigendian_dword(data+42, 82);   /* offset */
  588     put_bigendian_dword(data+46, resource_length);  /* length */
  589     /* finder info */
  590     memcpy(data+50, "EPSF", 4);     /* file type */
  591     memcpy(data+54, "MSWD", 4);     /* file creator */
  592     data[58] = 1;           /* ??? need to check finder info */
  593     gfile_write(f, data, 82);
  594 
  595     /* Now copy the resource fork */
  596     if (write_resource_pict(f, pictname) <= 0)
  597     return -1;
  598     return 0;
  599 }
  600 
  601 /* Write an AppleSingle file with a data fork containing EPSF
  602  * and a resource fork containing a preview as a single PICT 
  603  * with id=256.
  604  */
  605 int
  606 write_applesingle(GFile *f, LPCTSTR epsname, LPCTSTR pictname)
  607 {
  608     unsigned long resource_length;
  609     unsigned long data_length;
  610     unsigned char data[256];
  611     unsigned char *buffer;
  612     GFile *epsfile;
  613     unsigned long len;
  614     unsigned int count;
  615     int code = 0;
  616 
  617     buffer = (unsigned char *)malloc(COPY_BUF_SIZE);
  618     if (buffer == (unsigned char *)NULL)
  619     return -1;
  620 
  621     /* get length of data and resources */
  622     epsfile = gfile_open(epsname, gfile_modeRead);
  623     if (epsname == NULL) {
  624     free(buffer);
  625     return -1;
  626     }
  627     data_length = gfile_get_length(epsfile);
  628     resource_length = write_resource_pict(NULL, pictname);
  629 
  630     memset(data, 0, sizeof(data));
  631     memcpy(data, apple_single_magic, 4);    /* magic signature */
  632     put_bigendian_dword(data+4, 0x00020000);    /* version */
  633     /* 16 bytes filler */
  634     put_bigendian_word(data+24, 3); /* 3 entries, finder, data and resource */
  635     /* finder descriptor */
  636     put_bigendian_dword(data+26, 9);    /* finder id */
  637     put_bigendian_dword(data+30, 62);   /* offset */
  638     put_bigendian_dword(data+34, 32);   /* length */
  639     /* data descriptor */
  640     put_bigendian_dword(data+38, 1);    /* data fork id */
  641     put_bigendian_dword(data+42, 94);   /* offset */
  642     put_bigendian_dword(data+46, data_length);  /* length */
  643     /* resource descriptor */
  644     put_bigendian_dword(data+50, 2);    /* resource fork id */
  645     put_bigendian_dword(data+54, 94+data_length);   /* offset */
  646     put_bigendian_dword(data+58, resource_length);  /* length */
  647     /* finder info */
  648     memcpy(data+62, "EPSF", 4);     /* file type */
  649     memcpy(data+66, "MSWD", 4);     /* file creator */
  650     data[70] = 1;           /* ??? need to check finder info */
  651     gfile_write(f, data, 94);
  652 
  653     /* Copy data fork */
  654     len = data_length;
  655     while ( (count = (unsigned int)min(len,COPY_BUF_SIZE)) != 0 ) {
  656     count = (int)gfile_read(epsfile, buffer, count);
  657     gfile_write(f, buffer, count);
  658     if (count == 0) {
  659         len = 0;
  660         code = -1;
  661     }
  662     else
  663         len -= count;
  664     }
  665     gfile_close(epsfile);
  666     free(buffer);
  667     if (code < 0)
  668     return code;
  669 
  670     /* Now copy the resource fork */
  671     if (write_resource_pict(f, pictname) <= 0)
  672     return -1;
  673     return 0;
  674 }
  675 
  676 
  677 /* Write a MacBinary file with a data fork containing EPSF
  678  * and a resource fork containing a preview as a single PICT 
  679  * with id=256.
  680  */
  681 int
  682 write_macbin(GFile *f, const char *name, LPCTSTR epsname, LPCTSTR pictname)
  683 {
  684     unsigned char *buffer;
  685     unsigned char data[128];
  686     const char *macname;
  687     int macname_length;
  688     unsigned long data_length;
  689     unsigned long resource_length;
  690     unsigned long len;
  691     unsigned int count;
  692     int code = 0;
  693     GFile *epsfile;
  694     time_t now = time(NULL);
  695     now += 2082844800LU;    /* convert from Unix to Mac time */
  696     macname = name;
  697     if (name[0] == '\0')    /* we are writing to stdout */
  698     macname = "Unknown";
  699 
  700     buffer = (unsigned char *)malloc(COPY_BUF_SIZE);
  701     if (buffer == (unsigned char *)NULL)
  702     return -1;
  703 
  704     /* get length of data and resources */
  705     epsfile = gfile_open(epsname, gfile_modeRead);
  706     if (epsname == NULL) {
  707     free(buffer);
  708     return -1;
  709     }
  710     data_length = gfile_get_length(epsfile);
  711     resource_length = write_resource_pict(NULL, pictname);
  712 
  713     /* MacBinary I header */
  714     memset(data, 0, sizeof(data));
  715     data[0] = 0;            /* version */
  716     macname_length = min(63, (int)strlen(macname));
  717     data[1] = (unsigned char)macname_length;
  718     memcpy(data+2, macname, macname_length);
  719     memcpy(data+65, "EPSF", 4);     /* file type */
  720     memcpy(data+69, "MSWD", 4);     /* file creator */
  721     data[73] = 1;           /* finder flags */
  722     put_bigendian_dword(data+83, data_length);
  723     put_bigendian_dword(data+87, resource_length);
  724     put_bigendian_dword(data+91, (DWORD)now);   /* creation date */
  725     put_bigendian_dword(data+95, (DWORD)now);   /* last modified date */
  726     gfile_write(f, data, 128);
  727     
  728     /* copy data fork */
  729     len = data_length;
  730     while ( (count = (unsigned int)min(len,COPY_BUF_SIZE)) != 0 ) {
  731     count = (int)gfile_read(epsfile, buffer, count);
  732     gfile_write(f, buffer, count);
  733     if (count == 0) {
  734         len = 0;
  735         code = -1;
  736     }
  737     else
  738         len -= count;
  739     }
  740     gfile_close(epsfile);
  741     free(buffer);
  742     if (code < 0)
  743     return code;
  744 
  745     /* Pad to 128 byte boundary */
  746     memset(data, 0, sizeof(data));
  747     count = data_length & 127;
  748     if (count)
  749     gfile_write(f, data, 128-count);
  750 
  751     /* Now copy the resource fork */
  752     if (write_resource_pict(f, pictname) <= 0)
  753     return -1;
  754 
  755     /* Pad to 128 byte boundary */
  756     count = resource_length & 127;
  757     if (count)
  758     gfile_write(f, data, 128-count);
  759 
  760     return 0;
  761 }
  762 
  763 
  764 /* Returns -1 for error, 0 for Mac and 1 for non-Mac */
  765 /* If Macintosh format and verbose, print some details to stdout */
  766 int dump_macfile(LPCTSTR filename, int verbose)
  767 {
  768     CMACFILE *mac;
  769     const char *p;
  770     GFile *f = gfile_open(filename, gfile_modeRead);
  771     if (f == NULL)
  772     return -1;
  773     mac = get_mactype(f);
  774     if (mac)
  775         get_pict(f, mac, (verbose > 1));
  776     
  777     gfile_close(f);
  778 
  779     if (mac == NULL)
  780     return 1;
  781     if (verbose) {
  782     switch (mac->type) {
  783         case CMAC_TYPE_SINGLE:
  784         p = "AppleSingle";
  785         break;
  786         case CMAC_TYPE_DOUBLE:
  787         p = "AppleDouble";
  788         break;
  789         case CMAC_TYPE_MACBIN:
  790         p = "MacBinary";
  791         break;
  792         case CMAC_TYPE_RSRC:
  793         p = "Resource";
  794         break;
  795         default:
  796         p = "Unknown";
  797     }
  798     fprintf(stdout, "Macintosh Binary Format: %s\n", p);
  799     fprintf(stdout, " File Type: %c%c%c%c\n", 
  800         mac->file_type[0], mac->file_type[1], 
  801         mac->file_type[2], mac->file_type[3]);
  802     fprintf(stdout, " File Creator: %c%c%c%c\n", 
  803         mac->file_creator[0], mac->file_creator[1],
  804         mac->file_creator[2], mac->file_creator[3]);
  805     fprintf(stdout, " Finder Info: %ld %ld\n", 
  806         mac->finder_begin, mac->finder_length);
  807     fprintf(stdout, " Data Fork: %ld %ld\n", 
  808         mac->data_begin, mac->data_length);
  809     fprintf(stdout, " Resource Fork: %ld %ld\n", 
  810         mac->resource_begin, mac->resource_length);
  811     fprintf(stdout, " PICT: %ld %ld, 0x%lx 0x%lx\n", 
  812         mac->pict_begin, mac->pict_length,
  813         mac->pict_begin, mac->pict_length);
  814     }
  815     free(mac);
  816     return 0;
  817 }
  818 
  819 #ifdef STANDALONE
  820 /* To compile standalone for Windows,
  821  * cl -D_Windows -D__WIN32__ -DSTANDALONE -Isrc -Isrcwin
  822  *    src/cmac.c obj/wfile.obj obj/calloc.obj
  823  */
  824 
  825 
  826 int debug;
  827 
  828 
  829 void usage(void)
  830 {
  831     fprintf(stdout, "Usage:\n\
  832     File info: cmac -i input.eps\n\
  833     Extract data fork: cmac -d input output\n\
  834     Extract PICT: cmac -x input.eps output.pict\n\
  835     Write AppleSingle: cmac -1 input.eps input.pict output.eps\n\
  836     Write AppleDouble: cmac -2 input.pict ._output.eps\n\
  837     Write MacBinary: cmac -b input.eps input.pict output.eps\n\
  838 ");
  839 }
  840 
  841 int main(int argc, char *argv[])
  842 {
  843     GFile *f;
  844     CMACFILE *mac;
  845     int code = 0;
  846     if (argc < 2) {
  847     usage();
  848     return 1;
  849     }
  850  
  851     if (argv[1][0] != '-') {
  852     usage();
  853     return 1;
  854     }
  855     switch (argv[1][1]) {
  856     case 'i':
  857         if (argc != 3) {
  858         usage();
  859         return 1;
  860         }
  861         if (dump_macfile(argv[2], 2) == 1)
  862         fprintf(stdout, "Not a Macintosh Resource, MacBinary, AppleSingle or AppleDouble file";
  863         break;
  864     case 'd':
  865         /* Extract data fork */
  866         if (argc != 4) {
  867         usage();
  868         return 1;
  869         }
  870         f = gfile_open(argv[2], gfile_modeRead);
  871         if (f == NULL) {
  872         fprintf(stdout, "Failed to open file \042%s\042\n", argv[1]);
  873         return -1;
  874         }
  875         mac = get_mactype(f);
  876         if (mac == NULL) {
  877         fprintf(stdout, "Not a Mac file with resource fork\n");
  878         code = 1;
  879         }
  880         if (code == 0) {
  881         code = extract_mac_data(f, argv[3], 
  882             mac->data_begin, mac->data_length, 0);
  883         if (code)
  884             fprintf(stdout, "Failed to extract data fork.\n");
  885         else
  886             fprintf(stdout, "Success\n");
  887         }
  888         gfile_close(f);
  889         break;
  890     case 'x':
  891         /* Extract PICT preview */
  892         if (argc != 4) {
  893         usage();
  894         return 1;
  895         }
  896         f = gfile_open(argv[2], gfile_modeRead);
  897         if (f == NULL) {
  898         fprintf(stdout, "Failed to open file \042%s\042\n", argv[1]);
  899         return -1;
  900         }
  901         mac = get_mactype(f);
  902         if (mac == NULL) {
  903         fprintf(stdout, "Not a Mac file with resource fork\n");
  904         code = 1;
  905         }
  906         if (get_pict(f, mac, FALSE) == 0) {
  907         if (extract_mac_pict(f, mac, argv[3]) != 0)
  908             fprintf(stdout, "Failed to find PICT id=256 or write file\n");
  909         else
  910             fprintf(stdout, "Success\n");
  911             
  912         }
  913         else {
  914             fprintf(stdout, "Resource fork didn't contain PICT preview\n");
  915         }
  916         gfile_close(f);
  917         break;
  918     case 'm':
  919         /* Create MacBinary */
  920         if (argc != 5) {
  921         usage();
  922         return 1;
  923         }
  924         f = gfile_open(argv[4], gfile_modeWrite | gfile_modeCreate);
  925         if (f == NULL) {
  926         fprintf(stdout, "Failed to create file \042%s\042\n", argv[3]);
  927         return -1;
  928         }
  929         code = write_macbin(f, argv[2], argv[2], argv[3]);
  930         if (code != 0)
  931         fprintf(stdout, "Failed to write MacBinary\n");
  932         else
  933         fprintf(stdout, "Success at writing MacBinary\n");
  934         gfile_close(f);
  935         break;
  936     case '1':
  937         /* Create AppleSingle */
  938         if (argc != 5) {
  939         usage();
  940         return 1;
  941         }
  942         f = gfile_open(argv[4], gfile_modeWrite | gfile_modeCreate);
  943         if (f == NULL) {
  944         fprintf(stdout, "Failed to create file \042%s\042\n", argv[3]);
  945         return -1;
  946         }
  947         code = write_applesingle(f, argv[2], argv[3]);
  948         if (code != 0)
  949         fprintf(stdout, "Failed to write AppleSingle\n");
  950         else
  951         fprintf(stdout, "Success at writing AppleSingle\n");
  952         gfile_close(f);
  953         break;
  954     case '2':
  955         /* Create AppleDouble */
  956         if (argc != 4) {
  957         usage();
  958         return 1;
  959         }
  960         f = gfile_open(argv[3], gfile_modeWrite | gfile_modeCreate);
  961         if (f == NULL) {
  962         fprintf(stdout, "Failed to create file \042%s\042\n", argv[3]);
  963         return -1;
  964         }
  965         code = write_appledouble(f, argv[2]);
  966         if (code != 0)
  967         fprintf(stdout, "Failed to write AppleDouble\n");
  968         else
  969         fprintf(stdout, "Success at writing AppleDouble\n");
  970         gfile_close(f);
  971         break;
  972     default:
  973         usage();
  974         return 1;
  975     }
  976 
  977     return code;
  978 }
  979 #endif