Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /****************************************************************
  2.     MacBinaryIII.c
  3.  
  4.     Copyright  1997 Christopher Evans (cevans@poppybank.com)
  5.  
  6.     Basic encoding and decoding of Macintosh files to the
  7.     MacBinary III spec.
  8.  
  9.  This file is part of the MacBinaryIII_src_C.sit package
  10.  see macbin3.h for more information
  11.  
  12. ****************************************************************/
  13.  
  14. /*****************************************************************************/
  15. /*  Includes                                                                 */
  16. /*****************************************************************************/
  17.  
  18. #include <string.h>
  19. #include <stdio.h>
  20. #include "macbin3.h"
  21.  
  22. /*****************************************************************************/
  23. /*  Macros, typedefs                                                         */
  24. /*****************************************************************************/
  25.  
  26. /* source (the macbinary file) will be deleted */
  27. #define DELETE_MACBINARY_SOURCE
  28.  
  29. /* enable encoding
  30. #define INCLUDE_ENCODE_MACBINARY         */
  31.  
  32. /* enable decoding */
  33. #define INCLUDE_DECODE_MACBINARY
  34.  
  35. /* include own CRC 32 Bit Calculation
  36. #define INCLUDE_CRC32CALC               */
  37.  
  38. /* produce some helpful printouts for tracing
  39. #define TRACE_MACBINARY   */
  40.  
  41.  
  42.  
  43. #define LONG_AT_OFFSET(data, offset) *((long *)((unsigned char *)&data[offset]))
  44. #define WORD_AT_OFFSET(data, offset) *((Word *)((unsigned char *)&data[offset]))
  45. #define BYTE_AT_OFFSET(data, offset) *((Byte *)((unsigned char *)&data[offset]))
  46. #define PTR_AT_OFFSET(data, offset)  ((Ptr)((unsigned char *)&data[offset]))
  47.  
  48. typedef     unsigned short      Word;
  49.  
  50. #define kOldVersionOffset               0
  51. #define kFileNameLengthOffset           1
  52. #define kFileNameOffset                 2
  53. #define kFileTypeOffset                 65
  54. #define kFileCreatorOffset              69
  55. #define kFinderFlagsHiOffset            73
  56. #define kVersionCheckZero               74
  57. #define kFileVPositionOffset            75
  58. #define kFileHPositionOffset            77
  59. #define kFileFolderIDOffset             79
  60. #define kProtectedFlagOffset            81
  61. #define kVersionOneCheckZero            82
  62. #define kDataForkLengthOffset           83
  63. #define kResourceForkLengthOffset       87
  64. #define kFileCreationDateOffset         91
  65. #define kFileModificationDateOffset     95
  66. #define kGetInfoCommentLengthOffset     99
  67. #define kFinderFlagsLowOffset           101
  68. #define kMacbinarySigOffset             102
  69. #define kFilenameScriptOffset           106
  70. #define kExtendedFinderFlagsOffset      107
  71. #define kTotalFileLengthOffset          116
  72. #define kSecondaryHeaderLengthOffset    120
  73. #define kCurrentVersionOffset           122
  74. #define kMinimumVersionOffset           123
  75. #define kCRCOffset                      124
  76.  
  77. #define kResourceForkMaxLen             (1024 * 1024 * 16)
  78.  
  79.  
  80. /*****************************************************************************/
  81. /*  Module level Vars                                                        */
  82. /*****************************************************************************/
  83.  
  84. #ifdef INCLUDE_CRC32CALC
  85. static unsigned long crc_table[256] = {
  86.   0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
  87.   0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
  88.   0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
  89.   0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
  90.   0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
  91.   0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
  92.   0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
  93.   0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
  94.   0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
  95.   0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
  96.   0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
  97.   0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
  98.   0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
  99.   0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
  100.   0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
  101.   0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
  102.   0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
  103.   0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
  104.   0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
  105.   0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
  106.   0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
  107.   0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
  108.   0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
  109.   0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
  110.   0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
  111.   0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
  112.   0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
  113.   0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
  114.   0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
  115.   0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
  116.   0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
  117.   0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
  118.   0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
  119.   0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
  120.   0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
  121.   0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
  122.   0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
  123.   0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
  124.   0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
  125.   0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
  126.   0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
  127.   0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
  128.   0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
  129.   0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
  130.   0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
  131.   0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
  132.   0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
  133.   0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
  134.   0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
  135.   0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
  136.   0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
  137.   0x2d02ef8dL
  138. };
  139. #endif
  140.  
  141.  
  142. /*****************************************************************************/
  143. /*  Prototypes                                                               */
  144. /*****************************************************************************/
  145.  
  146. static Boolean  HeaderIsMacBinary(char *header,
  147.                                   Word *version,
  148.                                   long maxDataLen);
  149. static Boolean FSpExists(FSSpec *file);
  150. #ifdef INCLUDE_CRC32CALC
  151. static unsigned long crc32(unsigned long seed, unsigned char *p, size_t len);
  152. #else
  153. extern unsigned long crc32(unsigned long seed, unsigned char *p, size_t len);
  154. #endif
  155. static OSErr GetDesktopComment(FSSpec *file, char*comment, long *length);
  156. static OSErr SetDesktopComment(FSSpec *file, char*comment, long length);
  157. static Handle  EncodeMacbinary(FSSpec *file);
  158. static OSErr   DecodeMacBinary(Handle data, FSSpec *destination);
  159.  
  160. /*****************************************************************************/
  161. /*  Functions                                                                */
  162. /*****************************************************************************/
  163.  
  164.  
  165. #ifdef INCLUDE_CRC32CALC
  166. /* taken from the mcvert source code */
  167. static unsigned long crc32(unsigned long seed, unsigned char *p, size_t len)
  168. {
  169.     unsigned long hold;     /* crc computed so far */
  170.     size_t i;               /* index into data */
  171.  
  172.     hold = seed;                   /* start with seed */
  173.     for (i = 0; i < len; i++, p++)
  174.         {
  175.         hold ^= (*p << 8);
  176.         hold  = (hold << 8) ^ crc_table[(unsigned char) (hold >> 8)];
  177.         }
  178.  
  179.     return (hold);
  180. }               /* crc32() */
  181. #endif
  182.  
  183.  
  184.  
  185. static Boolean FSpExists(FSSpec *file)
  186. {
  187.     FInfo   fndrInfo;
  188.  
  189.     return FSpGetFInfo(file, &fndrInfo) == noErr;
  190. }
  191.  
  192.  
  193. static Boolean  HeaderIsMacBinary(char *header,
  194.                                   Word *version,
  195.                                   long maxDataLen)
  196. {
  197.     Boolean isIt = false;
  198.     unsigned long resourceForkLength, dataForkLength, df_rf_length;
  199.     short commentLength;
  200.     Byte    mbVersion;
  201.  
  202. #ifdef TRACE_MACBINARY
  203. printf("\n\n Function HeaderIsMacBinary(): ");
  204. #endif
  205.  
  206.     if(LONG_AT_OFFSET(header, kMacbinarySigOffset) == 'mBIN')
  207.         {
  208.         isIt = true;
  209.         mbVersion = 130;
  210.         }
  211.     else
  212.         if(BYTE_AT_OFFSET(header, kVersionCheckZero) == 0 &&
  213.             BYTE_AT_OFFSET(header, kOldVersionOffset) == 0)
  214.             {
  215.             if(WORD_AT_OFFSET(header, kCRCOffset) ==
  216.                crc32(0, (unsigned char*) &header, 124))
  217.                 {
  218.                 isIt = true;
  219.                 mbVersion = 129;
  220.                 }
  221.             else
  222.                 {
  223.                 if(BYTE_AT_OFFSET(header, kVersionOneCheckZero) == 0)
  224.                     {
  225.                     isIt = true;
  226.                     mbVersion = 128;
  227.                     }
  228.                 }
  229.             }
  230.  
  231. #ifdef TRACE_MACBINARY
  232. printf("\n           mbVersion: %d",mbVersion);
  233. #endif
  234.  
  235.     resourceForkLength = LONG_AT_OFFSET(header, kResourceForkLengthOffset);
  236.     dataForkLength     = LONG_AT_OFFSET(header, kDataForkLengthOffset);
  237.     commentLength      = WORD_AT_OFFSET(header, kGetInfoCommentLengthOffset);
  238.     df_rf_length = dataForkLength + resourceForkLength;
  239.  
  240. #ifdef TRACE_MACBINARY
  241. printf("\n  resourceForkLength: %d",resourceForkLength);
  242. printf("\n      dataForkLength: %d",dataForkLength);
  243. printf("\n       commentLength: %d",commentLength);
  244. printf("\n        df_rf_length: %d",df_rf_length);
  245. printf("\n                                                 1. isIt: bool: %d",
  246.        isIt);
  247. printf("\n BYTE_AT_OFFSET(header, kFileNameLengthOffset) >= 1       bool: %d",
  248.        BYTE_AT_OFFSET(header, kFileNameLengthOffset) >= 1);
  249. printf("\n BYTE_AT_OFFSET(header, kFileNameLengthOffset) <= 31      bool: %d",
  250.        BYTE_AT_OFFSET(header, kFileNameLengthOffset) <= 31);
  251. printf("\n dataForkLength >= 0                                      bool: %d",
  252.        dataForkLength >= 0);
  253. printf("\n resourceForkLength >= 0                                  bool: %d",
  254.        resourceForkLength >= 0);
  255. printf("\n resourceForkLength <= 0x%8x                         bool: %d",
  256.        kResourceForkMaxLen, resourceForkLength <= kResourceForkMaxLen);
  257. printf("\n dataForkLength     <= %8u                           bool: %d",
  258.        maxDataLen, dataForkLength <= maxDataLen);
  259. printf("\n df_rf_length        > 0                                  bool: %d",
  260.        df_rf_length > 0);
  261. printf("\n df_rf_length       <= %8u                           bool: %d",
  262.        maxDataLen, df_rf_length <= maxDataLen);
  263. #endif
  264.  
  265.     if(isIt                                                &&
  266.        BYTE_AT_OFFSET(header, kFileNameLengthOffset) >=  1 &&
  267.        BYTE_AT_OFFSET(header, kFileNameLengthOffset) <= 31 &&
  268.        dataForkLength     >= 0                             &&
  269.        resourceForkLength >= 0                             &&
  270.        resourceForkLength <= kResourceForkMaxLen           &&
  271.        df_rf_length       > 0                              &&
  272.        df_rf_length       <= maxDataLen)
  273.         {
  274.         isIt = true;
  275.         }
  276.     else
  277.         isIt = false;   /* something is wrong with the header */
  278.  
  279. #ifdef TRACE_MACBINARY
  280. printf("\n                                                 2. isIt: bool: %d",
  281.        isIt);
  282. #endif
  283.  
  284.     if(version)
  285.         *version = mbVersion;
  286.     return isIt;
  287. }
  288.  
  289.  
  290.  
  291. Boolean FSpIsMacBinary(FSSpec *file)
  292. {
  293.     char header[128];
  294.     short dfRefNum = 0;
  295.     OSErr   err;
  296.     long    size;
  297.     Boolean isIt = false;
  298.     CInfoPBRec  pb;
  299.     long maxDataLen;
  300.  
  301.     memset(&pb, 0, sizeof(CInfoPBRec));
  302.     pb.hFileInfo.ioNamePtr   = file->name;
  303.     pb.hFileInfo.ioVRefNum   = file->vRefNum;
  304.     pb.hFileInfo.ioFDirIndex = 0;           /*  query a file */
  305.     pb.hFileInfo.ioDirID     = file->parID;
  306.     err = PBGetCatInfo(&pb,false);
  307.     maxDataLen = pb.hFileInfo.ioFlLgLen;
  308.  
  309.     memset(header, 0, 128);
  310.  
  311.     err = FSpOpenDF(file, fsRdPerm, &dfRefNum);
  312.     if(!err)
  313.         {
  314.         err = GetEOF(dfRefNum, &size);
  315.         if(size > 128)
  316.             {
  317.             size = 128;
  318.             err = FSRead(dfRefNum, &size, &header);
  319.  
  320.             if(err == noErr)
  321.                 {
  322.                 isIt = HeaderIsMacBinary(header, nil, maxDataLen);
  323.                 }
  324.             }
  325.         FSClose(dfRefNum);
  326.         }
  327.     return isIt;
  328. }
  329.  
  330.  
  331.  
  332. #ifdef INCLUDE_ENCODE_MACBINARY
  333.  
  334. static OSErr    GetDesktopComment(FSSpec *file, char*comment, long *length)
  335. {
  336.     DTPBRec     pb;
  337.     OSErr       err;
  338.  
  339.     pb.ioCompletion = nil;
  340.     pb.ioNamePtr = NULL;
  341.     pb.ioVRefNum = file->vRefNum;
  342.  
  343.     err = PBDTGetPath(&pb);
  344.  
  345.     if(err == noErr)
  346.         {
  347.         pb.ioNamePtr = file->name;
  348.         pb.ioDTBuffer = comment;
  349.         pb.ioDirID = file->parID;
  350.         err = PBDTGetComment(&pb, false);
  351.         *length = pb.ioDTActCount;
  352.         }
  353.     return err;
  354. }
  355.  
  356.  
  357.  
  358.  
  359. OSErr   EncodeMacbinaryFile(FSSpec *file)
  360. {
  361.     Handle data;
  362.     OSErr   err = paramErr;
  363.     short   dfRefNum;
  364.  
  365.     data = EncodeMacbinary(file);
  366.  
  367.     if(data)
  368.         {
  369.         if(file->name[0] > 27)
  370.             file->name[0] = 27;
  371.  
  372.         PtoCstr(file->name);
  373.         strcat((char*)file->name, ".bin");
  374.         CtoPstr((char *)file->name);
  375.  
  376.         FSpDelete(file);
  377.         if(FSpCreate(file, 'dMB3', 'mBIN', smSystemScript) == noErr)
  378.             {
  379.             err = FSpOpenDF(file, fsWrPerm, &dfRefNum);
  380.             if(err == noErr)
  381.                 {
  382.                 long    inOutCount = GetHandleSize(data);
  383.  
  384.                 HLock(data);
  385.                 err = FSWrite(dfRefNum,&inOutCount,*data);
  386.                 HUnlock(data);
  387.                 FSClose(dfRefNum);
  388.                 }
  389.             }
  390.         DisposeHandle(data);
  391.         }
  392.     return err;
  393. }
  394.  
  395.  
  396.  
  397.  
  398.  
  399. static Handle EncodeMacbinary(FSSpec *file)
  400. {
  401.     Handle result = nil;
  402.     FInfo   fndrInfo;
  403.     FXInfo  fndrXInfo;
  404.     OSErr   err;
  405.     CInfoPBRec  pb;
  406.     short   dfRefNum, rfRefNum;
  407.     long    ioCount;
  408.     char    buffer[128];
  409.     char    header[128];
  410.     char    comment[256];
  411.     long    resourceForkLength, dataForkLength, commentLength;
  412.  
  413.     memset(&header, 0, sizeof(header));
  414.     err = FSpGetFInfo(file, &fndrInfo);
  415.  
  416.     memset(&pb, 0, sizeof(CInfoPBRec));
  417.     pb.hFileInfo.ioNamePtr = file->name;
  418.     pb.hFileInfo.ioVRefNum = file->vRefNum;
  419.     pb.hFileInfo.ioFDirIndex = 0;           //query a file
  420.     pb.hFileInfo.ioDirID = file->parID;
  421.     err = PBGetCatInfo(&pb,false);
  422.  
  423.     fndrXInfo = pb.hFileInfo.ioFlXFndrInfo;
  424.  
  425.     BYTE_AT_OFFSET(header, kFileNameLengthOffset) = file->name[0];
  426.     BlockMoveData( &(file->name[1]),
  427.                    PTR_AT_OFFSET(header,
  428.                    kFileNameOffset),
  429.                    file->name[0]);
  430.     LONG_AT_OFFSET(header, kFileTypeOffset)    = fndrInfo.fdType;
  431.     LONG_AT_OFFSET(header, kFileCreatorOffset) = fndrInfo.fdCreator;
  432.  
  433.     BYTE_AT_OFFSET(header, kFinderFlagsHiOffset) =
  434.                                           (fndrInfo.fdFlags & 0xFF00) >> 8;
  435.     BYTE_AT_OFFSET(header, kFinderFlagsLowOffset) =
  436.                                           (fndrInfo.fdFlags & 0x00FF);
  437.  
  438.     WORD_AT_OFFSET(header, kFileVPositionOffset) = fndrInfo.fdLocation.v;
  439.     WORD_AT_OFFSET(header, kFileHPositionOffset) = fndrInfo.fdLocation.h;
  440.     WORD_AT_OFFSET(header, kFileFolderIDOffset)  = fndrInfo.fdFldr;
  441.  
  442.     LONG_AT_OFFSET(header, kFileCreationDateOffset) = pb.hFileInfo.ioFlCrDat;
  443.     LONG_AT_OFFSET(header, kFileModificationDateOffset) =
  444.                                                       pb.hFileInfo.ioFlMdDat;
  445.  
  446.     LONG_AT_OFFSET(header, kMacbinarySigOffset)        = 'mBIN';
  447.     BYTE_AT_OFFSET(header, kFilenameScriptOffset)      = fndrXInfo.fdScript;
  448.     BYTE_AT_OFFSET(header, kExtendedFinderFlagsOffset) = fndrXInfo.fdXFlags;
  449.  
  450.     LONG_AT_OFFSET(header, kTotalFileLengthOffset) = 0;
  451.     WORD_AT_OFFSET(header, kSecondaryHeaderLengthOffset) = 0;
  452.  
  453.     WORD_AT_OFFSET(header, kCurrentVersionOffset) = 130;
  454.     WORD_AT_OFFSET(header, kMinimumVersionOffset) = 129;
  455.  
  456.     err = FSpOpenDF(file,fsRdPerm,&dfRefNum);
  457.     if(err == noErr)
  458.         {
  459.         err = GetEOF(dfRefNum,&dataForkLength);
  460.         LONG_AT_OFFSET(header, kDataForkLengthOffset) = dataForkLength;
  461.         }
  462.     else
  463.         {
  464.         dfRefNum = 0;
  465.         }
  466.  
  467.     err = FSpOpenRF(file,fsRdPerm,&rfRefNum);
  468.     if(err == noErr)
  469.         {
  470.         err = GetEOF(rfRefNum,&resourceForkLength);
  471.         LONG_AT_OFFSET(header, kResourceForkLengthOffset) = resourceForkLength;
  472.         }
  473.     else
  474.         {
  475.         rfRefNum = 0;
  476.         }
  477.  
  478.     memset(comment, 0, 256);
  479.     if(GetDesktopComment(file, comment, &commentLength) != noErr)
  480.         commentLength = 0;
  481.  
  482.     WORD_AT_OFFSET(header, kGetInfoCommentLengthOffset) = commentLength;
  483.     WORD_AT_OFFSET(header, kCRCOffset) =
  484.                                      crc32( 0, (unsigned char*) &header, 124);
  485.  
  486.     result = TempNewHandle(0, &err);
  487.     if(result)
  488.         {
  489.         err = PtrAndHand(&header,result,128);
  490.  
  491.         if(dfRefNum && dataForkLength)
  492.             {
  493.             err = noErr;
  494.             while(dataForkLength > 0 && err == noErr)
  495.                 {
  496.                 ioCount = 128;
  497.                 err = FSRead(dfRefNum,&ioCount,&buffer);
  498.  
  499.                 if(err == noErr || err == eofErr)
  500.                     err = PtrAndHand(&buffer,result,128);
  501.  
  502.                 dataForkLength -= ioCount;
  503.                 }
  504.             }
  505.  
  506.         if(rfRefNum && resourceForkLength)
  507.             {
  508.             err = noErr;
  509.             while(resourceForkLength > 0 && err == noErr)
  510.                 {
  511.                 ioCount = 128;
  512.                 err = FSRead(rfRefNum,&ioCount,&buffer);
  513.  
  514.                 if(err == noErr || err == eofErr)
  515.                     err = PtrAndHand(&buffer,result,128);
  516.  
  517.                 resourceForkLength -= ioCount;
  518.                 }
  519.             }
  520.  
  521.         if(commentLength)
  522.             {
  523.             PtrAndHand(&comment,result,commentLength);
  524.             }
  525.         }
  526.  
  527.     if(rfRefNum)
  528.         FSClose(rfRefNum);
  529.  
  530.     if(dfRefNum)
  531.         FSClose(dfRefNum);
  532.  
  533.     return result;
  534. }
  535.  
  536. #endif /* INCLUDE_ENCODE_MACBINARY */
  537.  
  538.  
  539.  
  540. #ifdef INCLUDE_DECODE_MACBINARY
  541.  
  542. static OSErr    SetDesktopComment(FSSpec *file, char*comment, long length)
  543. {
  544.     DTPBRec     pb;
  545.     OSErr       err;
  546.  
  547.     pb.ioCompletion = nil;
  548.     pb.ioNamePtr = NULL;
  549.     pb.ioVRefNum = file->vRefNum;
  550.  
  551.     err = PBDTGetPath(&pb);
  552.  
  553.     if(err == noErr)
  554.         {
  555.         pb.ioNamePtr    = file->name;
  556.         pb.ioDTBuffer   = comment;
  557.         pb.ioDirID      = file->parID;
  558.         pb.ioDTReqCount = length;
  559.         err = PBDTSetComment(&pb, false);
  560.         }
  561.     return err;
  562. }
  563.  
  564.  
  565.  
  566.  
  567. OSErr   DecodeMacBinaryFile(FSSpec *source)
  568. {
  569.     Handle  data = nil;
  570.     OSErr   err;
  571.     short   dfRefNum = 0;
  572.     long    size;
  573.     FSSpec  McBin_source;
  574.  
  575.     memcpy(McBin_source.name,source->name,source->name[0]+1);
  576.     McBin_source.vRefNum = source->vRefNum;
  577.     McBin_source.parID   = source->parID;
  578.  
  579.     err = FSpOpenDF(source, fsRdPerm, &dfRefNum);
  580.     if(!err)
  581.         {
  582.         err = GetEOF(dfRefNum, &size);
  583.  
  584.         data = TempNewHandle(size, &err);
  585.  
  586.         if(data)
  587.             {
  588.             HLock(data);
  589.             err = FSRead(dfRefNum,&size,*data);
  590.             HUnlock(data);
  591.             }
  592.         FSClose(dfRefNum);
  593.         }
  594.  
  595.     if(data && err == noErr)
  596.         {
  597.         err =  DecodeMacBinary(data, source);
  598.         DisposeHandle(data);
  599.         }
  600.  
  601. #ifdef DELETE_MACBINARY_SOURCE
  602.     if (err == noErr)
  603.         err = FSpDelete(&McBin_source);
  604. #endif
  605.  
  606.     return err;
  607. }
  608.  
  609.  
  610.  
  611.  
  612.  
  613. static OSErr   DecodeMacBinary(Handle data, FSSpec *destination)
  614. {
  615.     Handle result = nil;
  616.     FInfo   fndrInfo;
  617.     OSErr   err;
  618.     CInfoPBRec  pb;
  619.     short   dfRefNum, rfRefNum;
  620.     long    ioCount;
  621.     char    header[128];
  622.     char    comment[256];
  623.     long    resourceForkLength, dataForkLength, commentLength;
  624.     Boolean isMacBinaryFile = false;
  625.     short   headerEnd = 128;
  626.     long    rfOffset;
  627.     long maxDataLen;
  628.  
  629.     memset(&pb, 0, sizeof(CInfoPBRec));
  630.     pb.hFileInfo.ioNamePtr   = destination->name;
  631.     pb.hFileInfo.ioVRefNum   = destination->vRefNum;
  632.     pb.hFileInfo.ioFDirIndex = 0;           /*  query a file */
  633.     pb.hFileInfo.ioDirID     = destination->parID;
  634.     err = PBGetCatInfo(&pb,false);
  635.     maxDataLen = pb.hFileInfo.ioFlLgLen;
  636.  
  637.     HLock(data);
  638.     memcpy(header, *data, 128);
  639.  
  640.      /* already checked with FSpIsMacBinary()    */
  641.     isMacBinaryFile = HeaderIsMacBinary(header, nil, maxDataLen);;
  642.  
  643.     if(!isMacBinaryFile)
  644.         return paramErr;
  645.  
  646.     if(WORD_AT_OFFSET(header, kSecondaryHeaderLengthOffset))
  647.         {
  648.         headerEnd = WORD_AT_OFFSET(header, kSecondaryHeaderLengthOffset);
  649.         headerEnd = (headerEnd + 127) & ~127L;
  650.         }
  651.  
  652.     resourceForkLength = LONG_AT_OFFSET(header, kResourceForkLengthOffset);
  653.     dataForkLength     = LONG_AT_OFFSET(header, kDataForkLengthOffset);
  654.     commentLength      = WORD_AT_OFFSET(header, kGetInfoCommentLengthOffset);
  655.  
  656.     memcpy( destination->name,
  657.             PTR_AT_OFFSET(header,
  658.             kFileNameLengthOffset),
  659.             BYTE_AT_OFFSET(header,
  660.             kFileNameLengthOffset));
  661.  
  662.     fndrInfo.fdType    = LONG_AT_OFFSET(header, kFileTypeOffset);
  663.     fndrInfo.fdCreator = LONG_AT_OFFSET(header, kFileCreatorOffset);
  664.  
  665.     fndrInfo.fdFlags = BYTE_AT_OFFSET(header, kFinderFlagsHiOffset);
  666.     fndrInfo.fdFlags << 8;
  667.     fndrInfo.fdFlags |= BYTE_AT_OFFSET(header, kFinderFlagsLowOffset);
  668.  
  669.     fndrInfo.fdLocation.v = WORD_AT_OFFSET(header, kFileVPositionOffset);
  670.     fndrInfo.fdLocation.h = WORD_AT_OFFSET(header, kFileHPositionOffset);
  671.     fndrInfo.fdFldr       = WORD_AT_OFFSET(header, kFileFolderIDOffset);
  672. /*
  673.     index = 1;
  674.     checkFile = *destination;
  675.     while(FSpExists(&checkFile))
  676.         {
  677.         checkFile = *destination;
  678.  
  679.         if(index < 10)
  680.             checkFile.name[++checkFile.name[0]] = '0' + index;
  681.         else
  682.             checkFile.name[++checkFile.name[0]] = ('a' - 10) + index;
  683.         index++;
  684.         }
  685.     *destination = checkFile;
  686. */
  687.     err = FSpCreate(destination,
  688.                     fndrInfo.fdCreator,
  689.                     fndrInfo.fdType,
  690.                     smSystemScript);
  691.  
  692.     dfRefNum = 0;
  693.     if(err == noErr)
  694.         {
  695.         err = FSpOpenDF(destination, fsRdWrPerm, &dfRefNum);
  696.         }
  697.  
  698.     if(err == noErr && dfRefNum)
  699.         {
  700.         ioCount = dataForkLength;
  701.         err = FSWrite(dfRefNum,&ioCount,*data + headerEnd);
  702.         FSClose(dfRefNum);
  703.         }
  704.  
  705.     rfRefNum = 0;
  706.     if(err == noErr)
  707.         {
  708.         err = FSpOpenRF(destination, fsRdWrPerm, &rfRefNum);
  709.         }
  710.  
  711.     rfOffset = headerEnd + dataForkLength;
  712.     rfOffset = (rfOffset + 127) & ~127L;
  713.  
  714.     if(err == noErr && rfRefNum)
  715.         {
  716.         ioCount = resourceForkLength;
  717.         err = FSWrite(rfRefNum,&ioCount,*data + rfOffset);
  718.         FSClose(rfRefNum);
  719.         }
  720.  
  721.     rfOffset += resourceForkLength;
  722.     rfOffset = (rfOffset + 127) & ~127L;
  723.  
  724.     if(err == noErr)
  725.        {
  726.         FSpSetFInfo(destination,&fndrInfo);
  727.  
  728.         memset(&pb, 0, sizeof(CInfoPBRec));
  729.         pb.hFileInfo.ioNamePtr   = destination->name;
  730.         pb.hFileInfo.ioVRefNum   = destination->vRefNum;
  731.         pb.hFileInfo.ioFDirIndex = 0;           /*  query a file */
  732.         pb.hFileInfo.ioDirID     = destination->parID;
  733.         err = PBGetCatInfo(&pb,false);
  734.  
  735.         if(err == noErr)
  736.             {
  737.             pb.hFileInfo.ioDirID   = destination->parID;
  738.             pb.hFileInfo.ioFlCrDat =
  739.                           LONG_AT_OFFSET(header, kFileCreationDateOffset);
  740.             pb.hFileInfo.ioFlMdDat =
  741.                           LONG_AT_OFFSET(header, kFileModificationDateOffset);
  742.             pb.hFileInfo.ioFlXFndrInfo.fdXFlags =
  743.                           BYTE_AT_OFFSET(header, kExtendedFinderFlagsOffset);
  744.             pb.hFileInfo.ioFlXFndrInfo.fdScript =
  745.                           BYTE_AT_OFFSET(header, kFilenameScriptOffset);
  746.             err = PBSetCatInfo(&pb, false);
  747.             }
  748.  
  749.         if(commentLength)
  750.             {
  751.             memcpy(comment,*data + rfOffset, commentLength);
  752.             SetDesktopComment(destination, comment, commentLength);
  753.             }
  754.  
  755.         }
  756.     HUnlock(data);
  757.     return err;
  758. }
  759.  
  760. #endif /*  INCLUDE_DECODE_MACBINARY  */
  761.  
  762.  
  763.  
  764.