macos.c
上传用户:andy_li
上传日期:2007-01-06
资源大小:1019k
文件大小:56k
源码类别:

压缩解压

开发平台:

MultiPlatform

  1. /*---------------------------------------------------------------------------
  2.   mac.c
  3.   Macintosh-specific routines for use with Info-ZIP's UnZip 5.4 and later.
  4.   Contains:
  5.                     do_wild ()
  6.                     mapattr ()
  7.                     checkdir ()
  8.                     version ()
  9.                     macmkdir ()
  10.                     macopen ()
  11.                     maccreat ()
  12.                     macread ()
  13.                     macwrite ()
  14.                     macclose ()
  15.                     maclseek ()
  16.                     FindNewExtractFolder ()
  17.                     SetFinderInfo ()
  18.                     isMacOSexfield ()
  19.                     makePPClong ()
  20.                     makePPCword ()
  21.                     PrintMacExtraInfo ()
  22.                     GetExtraFieldData ()
  23.                     DecodeMac3ExtraField ()
  24.                     DecodeJLEEextraField ()
  25.                     PrintTextEncoding ()
  26.                     MacGlobalsInit ()
  27.   ---------------------------------------------------------------------------*/
  28. /*****************************************************************************/
  29. /*  Includes                                                                 */
  30. /*****************************************************************************/
  31. #define UNZIP_INTERNAL
  32. #include "unzip.h"
  33. #include <script.h>
  34. #include "pathname.h"
  35. #include "helpers.h"
  36. #include "macstuff.h"
  37. #include "mactime.h"
  38. /*****************************************************************************/
  39. /*  Macros, typedefs                                                         */
  40. /*****************************************************************************/
  41. #define read_only   file_attr   /* for readability only */
  42. #define MKDIR(path)     macmkdir(path)
  43. /*****************************************************************************/
  44. /*  Global Vars                                                              */
  45. /*****************************************************************************/
  46. /*  Note: sizeof() returns the size of this allusion
  47.           13 is current length of "XtraStuf.mac:"      */
  48. extern const char ResourceMark[13]; /* var is initialized in file pathname.c */
  49. Boolean MacUnzip_Noisy;         /* MacUnzip_Noisy is also used by console */
  50. /*****************************************************************************/
  51. /*  Module level Vars                                                        */
  52. /*****************************************************************************/
  53. static int created_dir;        /* used in mapname(), checkdir() */
  54. static int renamed_fullpath;   /* ditto */
  55. static FSSpec CurrentFile;
  56. static MACINFO newExtraField;  /* contains all extra-field data */
  57. static firstcall_of_macopen = true;
  58. static short MacZipMode;
  59. static Boolean UseUT_ExtraField     = false;
  60. static Boolean IgnoreEF_Macfilename = false;
  61. /*****************************************************************************/
  62. /*  Prototypes                                                               */
  63. /*****************************************************************************/
  64. extern char *GetUnZipInfoVersions(void);
  65. static OSErr SetFinderInfo(FSSpec *spec, MACINFO *mi);
  66. static Boolean GetExtraFieldData(short *MacZipMode, MACINFO *mi);
  67. static uch *scanMacOSexfield(uch *ef_ptr, unsigned ef_len,
  68.                              short *MacZipMode);
  69. static Boolean isMacOSexfield(unsigned id, unsigned size, short *MacZipMode);
  70. static void PrintMacExtraInfo(void);
  71. static void DecodeMac3ExtraField(ZCONST uch *buff, MACINFO *mi);
  72. static void DecodeJLEEextraField(ZCONST uch *buff, MACINFO *mi);
  73. static char *PrintTextEncoding(short script);
  74. static void MakeMacOS_String(char *MacOS_Str,
  75.             const char SpcChar1, const char SpcChar2,
  76.             const char SpcChar3, const char SpcChar4);
  77. /*****************************************************************************/
  78. /*  Constants (strings, etc.)                                                */
  79. /*****************************************************************************/
  80. static ZCONST char Far CannotCreateFile[] = "error:  cannot create %sn";
  81. /*****************************************************************************/
  82. /*  Functions                                                                */
  83. /*****************************************************************************/
  84. #ifndef SFX
  85. /**********************/
  86. /* Function do_wild() */   /* for porting:  dir separator; match(ignore_case) */
  87. /**********************/
  88. char *do_wild(__G__ wildspec)
  89.     __GDEF
  90.     char *wildspec;         /* only used first time on a given dir */
  91. {
  92.     static DIR *dir = (DIR *)NULL;
  93.     static char *dirname, *wildname, matchname[FILNAMSIZ];
  94.     static int firstcall=TRUE, have_dirname;
  95.     static unsigned long dirnamelen;
  96.     struct dirent *file;
  97.     /* Even when we're just returning wildspec, we *always* do so in
  98.      * matchname[]--calling routine is allowed to append four characters
  99.      * to the returned string, and wildspec may be a pointer to argv[].
  100.      */
  101.     if (firstcall) {        /* first call:  must initialize everything */
  102.         firstcall = FALSE;
  103.         MacUnzip_Noisy = !uO.qflag;
  104.         if (MacUnzip_Noisy) printf("%s nn", GetUnZipInfoVersions());
  105.         /* break the wildspec into a directory part and a wildcard filename */
  106.         if ((wildname = strrchr(wildspec, ':')) == (char *)NULL) {
  107.             dirname = ":";
  108.             dirnamelen = 1;
  109.             have_dirname = FALSE;
  110.             wildname = wildspec;
  111.         } else {
  112.             ++wildname;     /* point at character after ':' */
  113.             dirnamelen = wildname - wildspec;
  114.             if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) {
  115.                 Info(slide, 0x201, ((char *)slide,
  116.                   "warning:  cannot allocate wildcard buffersn"));
  117.                 strcpy(matchname, wildspec);
  118.                 return matchname;   /* but maybe filespec was not a wildcard */
  119.             }
  120.             strncpy(dirname, wildspec, dirnamelen);
  121.             dirname[dirnamelen] = '';   /* terminate for strcpy below */
  122.             have_dirname = TRUE;
  123.         }
  124.         if ((dir = opendir(dirname)) != (DIR *)NULL) {
  125.             while ((file = readdir(dir)) != (struct dirent *)NULL) {
  126.                 if (match(file->d_name, wildname, 0)) {  /* 0 == case sens. */
  127.                     if (have_dirname) {
  128.                         strcpy(matchname, dirname);
  129.                         strcpy(matchname+dirnamelen, file->d_name);
  130.                     } else
  131.                         strcpy(matchname, file->d_name);
  132.                     return matchname;
  133.                 }
  134.             }
  135.             /* if we get to here directory is exhausted, so close it */
  136.             closedir(dir);
  137.             dir = (DIR *)NULL;
  138.         }
  139.         /* return the raw wildspec in case that works (e.g., directory not
  140.          * searchable, but filespec was not wild and file is readable) */
  141.         strcpy(matchname, wildspec);
  142.         return matchname;
  143.     }
  144.     /* last time through, might have failed opendir but returned raw wildspec */
  145.     if (dir == (DIR *)NULL) {
  146.         firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  147.         if (have_dirname)
  148.             free(dirname);
  149.         return (char *)NULL;
  150.     }
  151.     closedir(dir);     /* have read at least one dir entry; nothing left */
  152.     dir = (DIR *)NULL;
  153.     firstcall = TRUE;  /* reset for new wildspec */
  154.     if (have_dirname)
  155.         free(dirname);
  156.     return (char *)NULL;
  157. } /* end function do_wild() */
  158. #endif /* !SFX */
  159. /***************************/
  160. /* Function open_outfile() */
  161. /***************************/
  162. int open_outfile(__G)         /* return 1 if fail */
  163.     __GDEF
  164. {
  165.     short outfd, fDataFork = TRUE;
  166.     OSErr err;
  167.     char CompletePath[NAME_MAX];
  168.     char ArchiveDir[NAME_MAX];
  169.     short CurrentFork;
  170.     unsigned exdirlen;
  171. #ifdef DLL
  172.     if (G.redirect_data)
  173.         return (redirect_outfile(__G) == FALSE);
  174. #endif
  175.     Trace((stderr, "open_outfile:  trying to open (%s) for writingn",
  176.       FnFilter1(G.filename)));
  177.     exdirlen = strlen(uO.exdir);
  178.     if (MacZipMode != UnKnown_EF)
  179.     {
  180.         fDataFork = (newExtraField.flags & EB_M3_FL_DATFRK) ? TRUE : FALSE;
  181.         if (IgnoreEF_Macfilename)  {
  182.             strcpy(ArchiveDir, &G.filename[exdirlen+1]);
  183.             G.filename[exdirlen+1] = '';
  184.             RfDfFilen2Real(ArchiveDir, ArchiveDir, MacZipMode,
  185.                       (newExtraField.flags & EB_M3_FL_DATFRK), &CurrentFork);
  186.             strcat(G.filename, ArchiveDir);
  187.         } else {        /* use the filename from extra-field */
  188.             G.filename[exdirlen+1] = '';
  189.             strcat(G.filename,newExtraField.FullPath);
  190.         }
  191.     }
  192.     else
  193.     {
  194.         if (!uO.aflag) {
  195.          /* unknown type documents */
  196.          /* all files are considered to be of type 'TEXT' and creator 'hscd' */
  197.          /* this is the default type for CDROM ISO-9660 without Apple extensions */
  198.             newExtraField.fpb.hFileInfo.ioFlFndrInfo.fdType    =  'TEXT';
  199.             newExtraField.fpb.hFileInfo.ioFlFndrInfo.fdCreator =  'hscd';
  200.         } else {
  201.          /* unknown text-files defaults to 'TEXT' */
  202.             newExtraField.fpb.hFileInfo.ioFlFndrInfo.fdType    =  'TEXT';
  203.          /* Bare Bones BBEdit */
  204.             newExtraField.fpb.hFileInfo.ioFlFndrInfo.fdCreator =  'R*ch';
  205.         }
  206.     }
  207.     GetCompletePath(CompletePath, G.filename, &CurrentFile, &err);
  208.     printerr("GetCompletePath open_outfile", (err != -43) && (err != 0),
  209.              err, __LINE__, __FILE__, CompletePath);
  210.     if ((outfd = maccreat(G.filename)) != -1) {
  211.         outfd = macopen(CompletePath, (fDataFork) ? 1 : 2);
  212.     }
  213.     if (outfd == -1) {
  214.         G.outfile = (FILE *)NULL;
  215.         Info(slide, 0x401, ((char *)slide, LoadFarString(CannotCreateFile),
  216.           FnFilter1(G.filename)));
  217.         return 1;
  218.     }
  219.     G.outfile = (FILE *)outfd;
  220.     Trace((stderr, "open_outfile:  successfully opened (%s) for writingn",
  221.       FnFilter1(G.filename)));
  222.     return 0;
  223. } /* end function open_outfile() */
  224. /**********************/
  225. /* Function mapattr() */
  226. /**********************/
  227. int mapattr(__G)
  228.     __GDEF
  229. {
  230.     /* only care about read-only bit, so just look at MS-DOS side of attrs */
  231.     G.pInfo->read_only = (unsigned)(G.crec.external_file_attributes & 1);
  232.     return 0;
  233. } /* end function mapattr() */
  234. /************************/
  235. /*  Function mapname()  */
  236. /************************/
  237.                              /* return 0 if no error, 1 if caution (filename */
  238. int mapname(__G__ renamed)   /*  truncated), 2 if warning (skip file because */
  239.     __GDEF                   /*  dir doesn't exist), 3 if error (skip file), */
  240.     int renamed;             /*  or 10 if out of memory (skip file) */
  241. {                            /*  [also IZ_VOL_LABEL, IZ_CREATED_DIR] */
  242.     char pathcomp[FILNAMSIZ];    /* path-component buffer */
  243.     char *pp, *cp=(char *)NULL;  /* character pointers */
  244.     char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
  245.     int quote = FALSE;           /* flags */
  246.     int error = 0;
  247.     register unsigned workch;    /* hold the character being tested */
  248. /*---------------------------------------------------------------------------
  249.     Initialize various pointers and counters and stuff.
  250.   ---------------------------------------------------------------------------*/
  251.     if (G.pInfo->vollabel)
  252.         return IZ_VOL_LABEL;    /* can't set disk volume labels on Macintosh */
  253.     /* can create path as long as not just freshening, or if user told us */
  254.     G.create_dirs = (!uO.fflag || renamed);
  255.     MacZipMode = false;
  256.     created_dir = FALSE;        /* not yet */
  257.     /* user gave full pathname:  don't prepend rootpath */
  258.     renamed_fullpath = (renamed && (*G.filename == '/'));
  259.     if (checkdir(__G__ (char *)NULL, INIT) == 10)
  260.         return 10;              /* initialize path buffer, unless no memory */
  261.     *pathcomp = '';           /* initialize translation buffer */
  262.     pp = pathcomp;              /* point to translation buffer */
  263.     if (uO.jflag)               /* junking directories */
  264.         cp = (char *)strrchr(G.filename, '/');
  265.     if (cp == (char *)NULL) {   /* no '/' or not junking dirs */
  266.         cp = G.filename;        /* point to internal zipfile-member pathname */
  267.         if (renamed_fullpath)
  268.             ++cp;               /* skip over leading '/' */
  269.     } else
  270.         ++cp;                   /* point to start of last component of path */
  271. /*---------------------------------------------------------------------------
  272.     Begin main loop through characters in filename.
  273.   ---------------------------------------------------------------------------*/
  274.     while ((workch = (uch)*cp++) != 0) {
  275.         if (quote) {                 /* if character quoted, */
  276.             *pp++ = (char)workch;    /*  include it literally */
  277.             quote = FALSE;
  278.         } else
  279.             switch (workch) {
  280.             case '/':             /* can assume -j flag not given */
  281.                 *pp = '';
  282.                 if ((error = checkdir(__G__ pathcomp, APPEND_DIR)) > 1)
  283.                     return error;
  284.                 pp = pathcomp;    /* reset conversion buffer for next piece */
  285.                 lastsemi = (char *)NULL;
  286.                                   /* leave directory semi-colons alone */
  287.                 break;
  288.             case ';':             /* VMS version (or DEC-20 attrib?) */
  289.                 lastsemi = pp;         /* keep for now; remove VMS ";##" */
  290.                 *pp++ = (char)workch;  /*  later, if requested */
  291.                 break;
  292.             case '26':          /* control-V quote for special chars */
  293.                 quote = TRUE;     /* set flag for next character */
  294.                 break;
  295.             default:
  296.                 /* allow European characters in filenames: */
  297.                 if (isprint(workch) || (128 <= workch && workch <= 254))
  298.                     *pp++ = (char)workch;
  299.             } /* end switch */
  300.     } /* end while loop */
  301.     *pp = '';                   /* done with pathcomp:  terminate it */
  302.     /* if not saving them, remove VMS version numbers (appended ";###") */
  303.     if (!uO.V_flag && lastsemi) {
  304.         pp = lastsemi + 1;
  305.         while (isdigit((uch)(*pp)))
  306.             ++pp;
  307.         if (*pp == '')          /* only digits between ';' and end:  nuke */
  308.             *lastsemi = '';
  309.     }
  310. /*---------------------------------------------------------------------------
  311.     Report if directory was created (and no file to create:  filename ended
  312.     in '/'), check name to be sure it exists, and combine path and name be-
  313.     fore exiting.
  314.   ---------------------------------------------------------------------------*/
  315.     if (G.filename[strlen(G.filename) - 1] == '/') {
  316.         checkdir(__G__ G.filename, GETPATH);
  317.         if (created_dir) {
  318.             if (QCOND2) {
  319.                 Info(slide, 0, ((char *)slide, "   creating: %sn",
  320.                   G.filename));
  321.             }
  322.             return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  323.         }
  324.         return 2;   /* dir existed already; don't look for data to extract */
  325.     }
  326.     if (*pathcomp == '') {
  327.         Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failedn",
  328.           G.filename));
  329.         return 3;
  330.     }
  331.     GetExtraFieldData(&MacZipMode, &newExtraField);
  332.     checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
  333.     checkdir(__G__ G.filename, GETPATH);
  334.     return error;
  335. } /* end function mapname() */
  336. /***********************/
  337. /* Function checkdir() */
  338. /***********************/
  339. int checkdir(__G__ pathcomp, flag)
  340.     __GDEF
  341.     char *pathcomp;
  342.     int flag;
  343. /*
  344.  * returns:  1 - (on APPEND_NAME) truncated filename
  345.  *           2 - path doesn't exist, not allowed to create
  346.  *           3 - path doesn't exist, tried to create and failed; or
  347.  *               path exists and is not a directory, but is supposed to be
  348.  *           4 - path is too long
  349.  *          10 - can't allocate memory for filename buffers
  350.  */
  351. {
  352.     static int rootlen = 0;   /* length of rootpath */
  353.     static char *rootpath;    /* user's "extract-to" directory */
  354.     static char *buildpath;   /* full path (so far) to extracted file */
  355.     static char *end;         /* pointer to end of buildpath ('') */
  356. #   define FN_MASK   7
  357. #   define FUNCTION  (flag & FN_MASK)
  358. /*---------------------------------------------------------------------------
  359.     APPEND_DIR:  append the path component to the path being built and check
  360.     for its existence.  If doesn't exist and we are creating directories, do
  361.     so for this one; else signal success or error as appropriate.
  362.   ---------------------------------------------------------------------------*/
  363.     if (FUNCTION == APPEND_DIR) {
  364.         int too_long = FALSE;
  365. #ifdef SHORT_NAMES
  366.         char *old_end = end;
  367. #endif
  368.         Trace((stderr, "appending dir segment [%s]n", pathcomp));
  369.         while ((*end = *pathcomp++) != '')
  370.             ++end;
  371. #ifdef SHORT_NAMES   /* path components restricted to 14 chars, typically */
  372.         if ((end-old_end) > FILENAME_MAX)  /* GRR:  proper constant? */
  373.             *(end = old_end + FILENAME_MAX) = '';
  374. #endif
  375.         /* GRR:  could do better check, see if overrunning buffer as we go:
  376.          * check end-buildpath after each append, set warning variable if
  377.          * within 20 of FILNAMSIZ; then if var set, do careful check when
  378.          * appending.  Clear variable when begin new path. */
  379.         if ((end-buildpath) > FILNAMSIZ-3)  /* need ':', one-char name, '' */
  380.             too_long = TRUE;                /* check if extracting directory? */
  381.         if (stat(buildpath, &G.statbuf)) {  /* path doesn't exist */
  382.             if (!G.create_dirs) { /* told not to create (freshening) */
  383.                 free(buildpath);
  384.                 return 2;         /* path doesn't exist:  nothing to do */
  385.             }
  386.             if (too_long) {
  387.                 Info(slide, 1, ((char *)slide,
  388.                   "checkdir error:  path too long: %sn", buildpath));
  389.                 free(buildpath);
  390.                 return 4;         /* no room for filenames:  fatal */
  391.             }
  392.             if (MKDIR(buildpath) == -1) {   /* create the directory */
  393.                 Info(slide, 1, ((char *)slide,
  394.                   "checkdir error:  cannot create %sn
  395.                  unable to process %s.n", buildpath, G.filename));
  396.                 free(buildpath);
  397.                 return 3;      /* path didn't exist, tried to create, failed */
  398.             }
  399.             created_dir = TRUE;
  400.         } else if (!S_ISDIR(G.statbuf.st_mode)) {
  401.             Info(slide, 1, ((char *)slide,
  402.               "checkdir error:  %s exists but is not directoryn
  403.                  unable to process %s.n", buildpath, G.filename));
  404.             free(buildpath);
  405.             return 3;          /* path existed but wasn't dir */
  406.         }
  407.         if (too_long) {
  408.             Info(slide, 1, ((char *)slide,
  409.               "checkdir error:  path too long: %sn", buildpath));
  410.             free(buildpath);
  411.             return 4;         /* no room for filenames:  fatal */
  412.         }
  413.         *end++ = ':';
  414.         *end = '';
  415.         Trace((stderr, "buildpath now = [%s]n", buildpath));
  416.         return 0;
  417.     } /* end if (FUNCTION == APPEND_DIR) */
  418. /*---------------------------------------------------------------------------
  419.     GETPATH:  copy full path to the string pointed at by pathcomp, and free
  420.     buildpath.
  421.   ---------------------------------------------------------------------------*/
  422.     if (FUNCTION == GETPATH) {
  423.         strcpy(pathcomp, buildpath);
  424.         Trace((stderr, "getting and freeing path [%s]n", pathcomp));
  425.         free(buildpath);
  426.         buildpath = end = (char *)NULL;
  427.         return 0;
  428.     }
  429. /*---------------------------------------------------------------------------
  430.     APPEND_NAME:  assume the path component is the filename; append it and
  431.     return without checking for existence.
  432.   ---------------------------------------------------------------------------*/
  433.     if (FUNCTION == APPEND_NAME) {
  434. #ifdef SHORT_NAMES
  435.         char *old_end = end;
  436. #endif
  437.         Trace((stderr, "appending filename [%s]n", pathcomp));
  438.         while ((*end = *pathcomp++) != '') {
  439.             ++end;
  440. #ifdef SHORT_NAMES  /* truncate name at 14 characters, typically */
  441.             if ((end-old_end) > FILENAME_MAX)      /* GRR:  proper constant? */
  442.                 *(end = old_end + FILENAME_MAX) = '';
  443. #endif
  444.             if ((end-buildpath) >= FILNAMSIZ) {
  445.                 *--end = '';
  446.                 Info(slide, 0x201, ((char *)slide,
  447.                   "checkdir warning:  path too long; truncatingn
  448.                    %sn                -> %sn", G.filename, buildpath));
  449.                 return 1;   /* filename truncated */
  450.             }
  451.         }
  452.         Trace((stderr, "buildpath now = [%s]n", buildpath));
  453.         return 0;  /* could check for existence here, prompt for new name... */
  454.     }
  455. /*---------------------------------------------------------------------------
  456.     INIT:  allocate and initialize buffer space for the file currently being
  457.     extracted.  If file was renamed with an absolute path, don't prepend the
  458.     extract-to path.
  459.   ---------------------------------------------------------------------------*/
  460.     if (FUNCTION == INIT) {
  461.         Trace((stderr, "initializing buildpath to "));
  462.         if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+2)) ==
  463.             (char *)NULL)
  464.             return 10;
  465.         if ((rootlen > 0) && !renamed_fullpath) {
  466.             strcpy(buildpath, rootpath);
  467.             end = buildpath + rootlen;
  468.         } else {
  469.             end = buildpath;
  470.             if (!renamed_fullpath && !uO.jflag) {
  471.                 *end++ = ':';           /* indicate relative path */
  472.             }
  473.             *end = '';
  474.         }
  475.         Trace((stderr, "[%s]n", buildpath));
  476.         return 0;
  477.     }
  478. /*---------------------------------------------------------------------------
  479.     ROOT:  if appropriate, store the path in rootpath and create it if neces-
  480.     sary; else assume it's a zipfile member and return.  This path segment
  481.     gets used in extracting all members from every zipfile specified on the
  482.     command line.
  483.   ---------------------------------------------------------------------------*/
  484. #if (!defined(SFX) || defined(SFX_EXDIR))
  485.     if (FUNCTION == ROOT) {
  486.         Trace((stderr, "initializing root path to [%s]n", pathcomp));
  487.         if (pathcomp == (char *)NULL) {
  488.             rootlen = 0;
  489.             return 0;
  490.         }
  491.         if ((rootlen = strlen(pathcomp)) > 0) {
  492.             if (pathcomp[rootlen-1] == ':') {
  493.                 pathcomp[--rootlen] = '';     /* strip trailing delimiter */
  494.             }
  495.             if (rootlen > 0 && (stat(pathcomp, &G.statbuf) ||
  496.                 !S_ISDIR(G.statbuf.st_mode)))       /* path does not exist */
  497.             {
  498.                 if (!G.create_dirs /* || iswild(pathcomp) */ ) {
  499.                     rootlen = 0;
  500.                     return 2;   /* skip (or treat as stored file) */
  501.                 }
  502.                 /* create the directory (could add loop here to scan pathcomp
  503.                  * and create more than one level, but why really necessary?) */
  504.                 if (MKDIR(pathcomp) == -1) {
  505.                     Info(slide, 1, ((char *)slide,
  506.                       "checkdir:  cannot create extraction directory: %sn",
  507.                       pathcomp));
  508.                     rootlen = 0;   /* path didn't exist, tried to create, and */
  509.                     return 3;  /* failed:  file exists, or 2+ levels required */
  510.                 }
  511.             }
  512.             if ((rootpath = (char *)malloc(rootlen+2)) == (char *)NULL) {
  513.                 rootlen = 0;
  514.                 return 10;
  515.             }
  516.             strcpy(rootpath, pathcomp);
  517.             rootpath[rootlen++] = ':';
  518.             rootpath[rootlen] = '';
  519.             Trace((stderr, "rootpath now = [%s]n", rootpath));
  520.         }
  521.         return 0;
  522.     }
  523. #endif /* !SFX || SFX_EXDIR */
  524. /*---------------------------------------------------------------------------
  525.     END:  free rootpath, immediately prior to program exit.
  526.   ---------------------------------------------------------------------------*/
  527.     if (FUNCTION == END) {
  528.         Trace((stderr, "freeing rootpathn"));
  529.         if (rootlen > 0) {
  530.             free(rootpath);
  531.             rootlen = 0;
  532.         }
  533.         return 0;
  534.     }
  535.     return 99;  /* should never reach */
  536. } /* end function checkdir() */
  537. /****************************/
  538. /* Function close_outfile() */
  539. /****************************/
  540. void close_outfile(__G)    /* GRR: change to return PK-style warning level */
  541.     __GDEF
  542. {
  543. #ifdef USE_EF_UT_TIME
  544.     iztimes z_utime;
  545.     unsigned eb_izux_flg;
  546. #endif
  547.     HParamBlockRec hpbr;
  548.     OSErr err;
  549.     FSSpec spec;
  550.     char CompletePath[NAME_MAX];
  551.     CInfoPBRec      fpb;
  552.     if (fileno(G.outfile) == 1)
  553.         return;         /* don't attempt to close or set time on stdout */
  554.     err = (OSErr)fclose(G.outfile);
  555.     printerr("macclose FSClose ",err, err, __LINE__, __FILE__, G.filename);
  556.     GetCompletePath(CompletePath, G.filename, &spec, &err);
  557.     printerr("GetCompletePath", err, err, __LINE__, __FILE__, G.filename);
  558.     fpb.hFileInfo.ioNamePtr = spec.name;
  559.     fpb.hFileInfo.ioVRefNum = spec.vRefNum;
  560.     fpb.hFileInfo.ioDirID = spec.parID;
  561.     fpb.hFileInfo.ioFDirIndex = 0;
  562.     hpbr.fileParam.ioNamePtr = spec.name;
  563.     hpbr.fileParam.ioVRefNum = spec.vRefNum;
  564.     hpbr.fileParam.ioDirID = spec.parID;
  565.     hpbr.fileParam.ioFDirIndex = 0;
  566.     err = PBGetCatInfoSync((CInfoPBPtr)&fpb);
  567.     printerr("PBGetCatInfoSync", err, err, __LINE__, __FILE__, G.filename);
  568.     fpb.hFileInfo.ioDirID = spec.parID;
  569.     if ((MacZipMode == UnKnown_EF) || UseUT_ExtraField ) {
  570. #ifdef USE_EF_UT_TIME
  571.         eb_izux_flg = ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
  572.                                        G.lrec.last_mod_dos_datetime, &z_utime, NULL);
  573.         if (G.extra_field &&
  574. #ifdef IZ_CHECK_TZ
  575.             G.tz_is_valid &&
  576. #endif
  577.             (eb_izux_flg & EB_UT_FL_MTIME))
  578.             {
  579.             fpb.hFileInfo.ioFlMdDat = UnixFtime2MacFtime(z_utime.mtime);
  580.             fpb.hFileInfo.ioFlCrDat = UnixFtime2MacFtime(z_utime.ctime);
  581.             }
  582. #ifdef DEBUG_TIME
  583.             {
  584.             struct tm *tp = gmtime(&z_utime.ctime);
  585.             printf(
  586.               "close_outfile:  Unix e.f. creat. time = %d/%2d/%2d  %2d:%2d:%2d -> %lu UTCn",
  587.               tp->tm_year, tp->tm_mon+1, tp->tm_mday,
  588.               tp->tm_hour, tp->tm_min, tp->tm_sec, z_utime.ctime);
  589.             tp = gmtime(&z_utime.mtime);
  590.             printf(
  591.               "close_outfile:  Unix e.f. modif. time = %d/%2d/%2d  %2d:%2d:%2d -> %lu UTCn",
  592.               tp->tm_year, tp->tm_mon+1, tp->tm_mday,
  593.               tp->tm_hour, tp->tm_min, tp->tm_sec, z_utime.mtime);
  594.             }
  595. #endif /* DEBUG_TIME */
  596. #else /* !USE_EF_UT_TIME */
  597.         TTrace((stderr, "close_outfile:  using DOS-Datetime ! n",
  598.               z_utime.mtime));
  599.         dtr.year = (((G.lrec.last_mod_dos_datetime >> 25) & 0x7f) + 1980);
  600.         dtr.month = ((G.lrec.last_mod_dos_datetime >> 21) & 0x0f);
  601.         dtr.day = ((G.lrec.last_mod_dos_datetime >> 16) & 0x1f);
  602.         dtr.hour = ((G.lrec.last_mod_dos_datetime >> 11) & 0x1f);
  603.         dtr.minute = ((G.lrec.last_mod_dos_datetime >> 5) & 0x3f);
  604.         dtr.second = ((G.lrec.last_mod_dos_datetime << 1) & 0x3e);
  605.         DateToSeconds(&dtr, (unsigned long *)&fpb.hFileInfo.ioFlMdDat);
  606.         fpb.hFileInfo.ioFlCrDat = fpb.hFileInfo.ioFlMdDat;
  607. #endif /* ?USE_EF_UT_TIME */
  608.         if (err == noErr)
  609.             err = PBSetCatInfoSync((CInfoPBPtr)&fpb);
  610.         if (err != noErr)
  611.             printf("error (%d): cannot set the time for %sn", err, G.filename);
  612.     }
  613.     /* set read-only perms if needed */
  614.     if ((err == noErr) && G.pInfo->read_only) {
  615.         err = PBHSetFLockSync(&hpbr);
  616.         printerr("PBHSetFLockSync",err,err,__LINE__,__FILE__,G.filename);
  617.     }
  618.     /* finally set FinderInfo */
  619.     if (MacZipMode != UnKnown_EF) {
  620.         err = SetFinderInfo(&CurrentFile, &newExtraField);
  621.         printerr("close_outfile SetFinderInfo ", err, err,
  622.                  __LINE__, __FILE__, G.filename);
  623.     }
  624. } /* end function close_outfile() */
  625. #ifndef SFX
  626. /************************/
  627. /*  Function version()  */
  628. /************************/
  629. void version(__G)
  630.     __GDEF
  631. {
  632. #if 0
  633.     char buf[40];
  634. #endif
  635.     sprintf((char *)slide, LoadFarString(CompiledWith),
  636. #ifdef __GNUC__
  637.       "gcc ", __VERSION__,
  638. #else
  639. #  if 0
  640.       "cc ", (sprintf(buf, " version %d", _RELEASE), buf),
  641. #  else
  642. #  ifdef __MWERKS__
  643.       "CodeWarrior C", "",
  644. #  else
  645. #  ifdef THINK_C
  646.       "Think C", "",
  647. #  else
  648. #  ifdef MPW
  649.       "MPW C", "",
  650. #  else
  651.       "unknown compiler", "",
  652. #  endif
  653. #  endif
  654. #  endif
  655. #  endif
  656. #endif
  657.       "MacOS",
  658. #if defined(foobar) || defined(FOOBAR)
  659.       " (Foo BAR)",    /* hardware or OS version */
  660. #else
  661.       "",
  662. #endif /* Foo BAR */
  663. #ifdef __DATE__
  664.       " on ", __DATE__
  665. #else
  666.       "", ""
  667. #endif
  668.     );
  669.     (*G.message)((zvoid *)&G, slide, (ulg)strlen((char *)slide), 0);
  670. } /* end function version() */
  671. #endif /* !SFX */
  672. /***********************/
  673. /* Function macmkdir() */
  674. /***********************/
  675. int macmkdir(char *path)
  676. {
  677.     OSErr err = -1;
  678.     OSErr err_rc;
  679.     char CompletePath[NAME_MAX];
  680.     FSSpec spec;
  681.     Boolean isDirectory = false;
  682.     short CurrentFork;
  683.     unsigned pathlen;
  684.     long dirID;
  685.     GetExtraFieldData(&MacZipMode, &newExtraField);
  686.     if (MacZipMode != UnKnown_EF) {
  687.         RfDfFilen2Real(CompletePath, G.filename, MacZipMode,
  688.                        (newExtraField.flags & EB_M3_FL_NOCHANGE), &CurrentFork);
  689.         if (CurrentFork == ResourceFork)
  690.             /* don't build a 'XtraStuf.mac:' dir  */
  691.             return 0;
  692.     }
  693.     if (!IgnoreEF_Macfilename) {
  694.         pathlen = strlen(path);
  695.         strcpy(path, uO.exdir);
  696.         strcat(path, ":");
  697.         strcat(path, newExtraField.FullPath);
  698.         path[pathlen] = 0x00;
  699.     }
  700.     GetCompletePath(CompletePath, path, &spec, &err);
  701.     printerr("GetCompletePath", (err != -43) && (err != -120) && (err != 0),
  702.              err, __LINE__, __FILE__, path);
  703.     err = FSpGetDirectoryID(&spec, &dirID, &isDirectory);
  704.     printerr("macmkdir FSpGetDirectoryID ", (err != -43) && (err != 0),
  705.              err, __LINE__, __FILE__, path);
  706.     if (err != -43)     /* -43 = file/directory not found  */
  707.         return 0;
  708.     else {
  709.         HParamBlockRec    hpbr;
  710.         hpbr.fileParam.ioCompletion = NULL;
  711.         hpbr.fileParam.ioNamePtr = spec.name;
  712.         hpbr.fileParam.ioVRefNum = spec.vRefNum;
  713.         hpbr.fileParam.ioDirID = spec.parID;
  714.         err = PBDirCreateSync(&hpbr);
  715.         printerr("macmkdir PBDirCreateSync ", err,
  716.                  err, __LINE__, __FILE__, CompletePath);
  717.         if (MacZipMode != UnKnown_EF) {
  718.             err_rc = SetFinderInfo(&spec, &newExtraField);
  719.             printerr("macmkdir SetFinderInfo ", err_rc,
  720.                      err_rc, __LINE__, __FILE__, CompletePath);
  721.         }
  722.     }
  723.     return (int)err;
  724. } /* macmkdir */
  725. /**********************/
  726. /* Function macopen() */
  727. /**********************/
  728. short macopen(char *sz, short nFlags)
  729. {
  730.     OSErr   err;
  731.     char    chPerms = (!nFlags) ? fsRdPerm : fsRdWrPerm;
  732.     short   nFRefNum;
  733.     static char CompletePath[NAME_MAX];
  734.     /* we only need the filespec of the zipfile;
  735.        filespec of the other files (to be extracted) will be
  736.        determined by open_outfile() */
  737.     if (firstcall_of_macopen) {
  738.         GetCompletePath(CompletePath, sz, &CurrentFile, &err);
  739.         printerr("GetCompletePath", (err != -43) && (err != 0),
  740.                  err, __LINE__, __FILE__, sz);
  741.         /* we are working only with pathnames, this can cause big problems
  742.          * on a Mac ...
  743.          */
  744.         if (CheckMountedVolumes(CompletePath) > 1)
  745.             DoWarnUserDupVol(CompletePath);
  746.         firstcall_of_macopen = false;
  747.     }
  748.     if (nFlags > 1) {
  749.         err = HOpenRF(CurrentFile.vRefNum, CurrentFile.parID, CurrentFile.name,
  750.                       chPerms, &nFRefNum);
  751.         printerr("HOpenRF", (err != -43) && (err != 0) && (err != -54),
  752.                  err, __LINE__, __FILE__, sz);
  753.     } else {
  754.         err = HOpen(CurrentFile.vRefNum, CurrentFile.parID, CurrentFile.name,
  755.                     chPerms, &nFRefNum);
  756.         printerr("HOpen", (err != -43) && (err != 0),
  757.                  err, __LINE__, __FILE__, sz);
  758.     }
  759.     if ( err || (nFRefNum == 1) )
  760.         return -1;
  761.     else {
  762.         if ( nFlags )
  763.             SetEOF( nFRefNum, 0 );
  764.         return nFRefNum;
  765.     }
  766. }
  767. /***********************/
  768. /* Function maccreat() */
  769. /***********************/
  770. short maccreat(char *sz)
  771. {
  772.     OSErr   err;
  773.     char scriptTag = newExtraField.fpb.hFileInfo.ioFlXFndrInfo.fdScript;
  774.     sz = sz;
  775.     /* Set fdScript in FXInfo
  776.      * The negative script constants (smSystemScript, smCurrentScript,
  777.      * and smAllScripts) don't make sense on disk.  So only use scriptTag
  778.      * if scriptTag >= smRoman (smRoman is 0).
  779.      * fdScript is valid if high bit is set (see IM-6, page 9-38)
  780.      */
  781.     scriptTag = (scriptTag >= smRoman) ?
  782.                 ((char)scriptTag | (char)0x80) : (smRoman);
  783.     newExtraField.fpb.hFileInfo.ioFlXFndrInfo.fdScript = scriptTag;
  784.     err = FSpCreate(&CurrentFile,
  785.                     newExtraField.fpb.hFileInfo.ioFlFndrInfo.fdCreator,
  786.                     newExtraField.fpb.hFileInfo.ioFlFndrInfo.fdType,
  787.                     newExtraField.fpb.hFileInfo.ioFlXFndrInfo.fdScript);
  788.     err = printerr("FSpCreate maccreat ", (err != -48) && (err != 0),
  789.                    err, __LINE__, __FILE__, G.filename);
  790.     if (err == noErr)
  791.         return noErr;
  792.     else
  793.         return -1;
  794. }
  795. /**********************/
  796. /* Function macread() */
  797. /**********************/
  798. short macread(short nFRefNum, char *pb, unsigned cb)
  799. {
  800.     long    lcb = cb;
  801.     (void)FSRead( nFRefNum, &lcb, pb );
  802.     return (short)lcb;
  803. }
  804. /***********************/
  805. /* Function macwrite() */
  806. /***********************/
  807. long macwrite(short nFRefNum, char *pb, unsigned cb)
  808. {
  809.     long    lcb = cb;
  810.     OSErr   err;
  811.     FILE    *stream;
  812.     if ( (nFRefNum == 1) || (nFRefNum == 2) )
  813.         {
  814.         stream = (nFRefNum == 1 ? stdout : stderr);
  815.         pb[cb] = '';           /* terminate C-string */
  816.                                  /* assumes writable buffer (e.g., slide[]) */
  817.                                  /* with room for one more char at end of buf */
  818.         MakeMacOS_String( pb, ' ', ' ', ' ', ' ');
  819.         lcb = fprintf(stream, pb);
  820.         }
  821.     else
  822.         err = FSWrite( nFRefNum, &lcb, pb );
  823.     if (err != 0)
  824.         {
  825.         errno = ERANGE;
  826.         return -1;
  827.         }
  828.     return (long)lcb;
  829. }
  830. /***********************/
  831. /* Function macclose() */
  832. /***********************/
  833. short macclose(short nFRefNum)
  834. {
  835. OSErr err;
  836. err = FSClose( nFRefNum );
  837. printerr("macclose FSClose ",err,err, __LINE__,__FILE__,G.filename);
  838. return err;
  839. }
  840. /***********************/
  841. /* Function maclseek() */
  842. /***********************/
  843. long maclseek(short nFRefNum, long lib, short nMode)
  844. {
  845.     ParamBlockRec   pbr;
  846.     if (nMode == SEEK_SET)
  847.         nMode = fsFromStart;
  848.     else if (nMode == SEEK_CUR)
  849.         nMode = fsFromMark;
  850.     else if (nMode == SEEK_END)
  851.         nMode = fsFromLEOF;
  852.     pbr.ioParam.ioRefNum = nFRefNum;
  853.     pbr.ioParam.ioPosMode = nMode;
  854.     pbr.ioParam.ioPosOffset = lib;
  855.     (void)PBSetFPosSync(&pbr);
  856.     return pbr.ioParam.ioPosOffset;
  857. }
  858. /***********************************/
  859. /* Function FindNewExtractFolder() */
  860. /***********************************/
  861. char *FindNewExtractFolder(char *ExtractPath)
  862. {
  863. char buffer[NAME_MAX];
  864. short count = 0, length = strlen(ExtractPath) - 2;
  865. OSErr err;
  866. FSSpec Spec;
  867. long theDirID;
  868. Boolean isDirectory;
  869. for (count = 0; count < 99; count++)
  870.     {
  871.     memset(buffer,0,sizeof(buffer));
  872.     ExtractPath[length] = 0;
  873.     sprintf(buffer,"%s%d",ExtractPath,count);
  874.     GetCompletePath(ExtractPath, buffer, &Spec,&err);
  875.     err = FSpGetDirectoryID(&Spec, &theDirID, &isDirectory);
  876.     if (err == -43) return ExtractPath;
  877.     }
  878. return ExtractPath; /* can't find unique path, defaults to Extract-Folder */
  879. }
  880. /* The following functions are dealing with the extra-field handling, only. */
  881. /****************************/
  882. /* Function SetFinderInfo() */
  883. /****************************/
  884. static OSErr SetFinderInfo(FSSpec *spec, MACINFO *mi)
  885. {
  886.     OSErr err;
  887.     CInfoPBRec      fpb;
  888.     fpb.hFileInfo.ioNamePtr   = (StringPtr) &(spec->name);
  889.     fpb.hFileInfo.ioVRefNum   = spec->vRefNum;
  890.     fpb.hFileInfo.ioDirID     = spec->parID;
  891.     fpb.hFileInfo.ioFDirIndex = 0;
  892.     err = PBGetCatInfo(&fpb, false);
  893.     printerr("PBGetCatInfo SetFinderInfo ", err, err,
  894.              __LINE__, __FILE__, G.filename);
  895.     if  ((MacZipMode == JohnnyLee_EF) || (MacZipMode == NewZipMode_EF))
  896.     {
  897.         if (!UseUT_ExtraField)  {
  898.             fpb.hFileInfo.ioFlCrDat = mi->fpb.hFileInfo.ioFlCrDat;
  899.             fpb.hFileInfo.ioFlMdDat = mi->fpb.hFileInfo.ioFlMdDat;
  900.         }
  901.         fpb.hFileInfo.ioFlFndrInfo   = mi->fpb.hFileInfo.ioFlFndrInfo;
  902.     }
  903.     if (MacZipMode == NewZipMode_EF)
  904.     {
  905.         if (uO.E_flag) PrintMacExtraInfo();
  906.         fpb.hFileInfo.ioFlXFndrInfo  = mi->fpb.hFileInfo.ioFlXFndrInfo;
  907.         fpb.hFileInfo.ioFVersNum  = mi->fpb.hFileInfo.ioFVersNum;
  908.         fpb.hFileInfo.ioACUser    = mi->fpb.hFileInfo.ioACUser;
  909.         if (!UseUT_ExtraField) {
  910.             fpb.hFileInfo.ioFlBkDat = mi->fpb.hFileInfo.ioFlBkDat;
  911. #ifdef USE_EF_UT_TIME
  912.             if (
  913. #ifdef IZ_CHECK_TZ
  914.                 G.tz_is_valid &&
  915. #endif
  916.                 !(mi->flags & EB_M3_FL_NOUTC))
  917.                 {
  918. #ifdef DEBUG_TIME
  919.             {
  920.             printf("nSetFinderInfo:  Mac modif: %lu local -> UTOffset: %d before AdjustForTZmoveMacn",
  921.               fpb.hFileInfo.ioFlCrDat, mi->Cr_UTCoffs);
  922.             }
  923. #endif /* DEBUG_TIME */
  924.                 fpb.hFileInfo.ioFlCrDat =
  925.                   AdjustForTZmoveMac(fpb.hFileInfo.ioFlCrDat, mi->Cr_UTCoffs);
  926.                 fpb.hFileInfo.ioFlMdDat =
  927.                   AdjustForTZmoveMac(fpb.hFileInfo.ioFlMdDat, mi->Md_UTCoffs);
  928.                 fpb.hFileInfo.ioFlBkDat =
  929.                   AdjustForTZmoveMac(fpb.hFileInfo.ioFlBkDat, mi->Bk_UTCoffs);
  930. #ifdef DEBUG_TIME
  931.             {
  932.             printf("SetFinderInfo:  Mac modif: %lu local -> UTOffset: %d after AdjustForTZmoveMacn",
  933.               fpb.hFileInfo.ioFlCrDat, mi->Cr_UTCoffs);
  934.             }
  935. #endif /* DEBUG_TIME */
  936.                 }
  937. #endif /* USE_EF_UT_TIME */
  938.         }
  939.         if (mi->FinderComment)  {
  940.             C2PStr(mi->FinderComment);
  941.             err = FSpDTSetComment(spec, (unsigned char *) mi->FinderComment);
  942.             printerr("FSpDTSetComment:",err , err,
  943.                      __LINE__, __FILE__, mi->FullPath);
  944.         }
  945.     }
  946.     /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  947.     fpb.hFileInfo.ioDirID = spec->parID;
  948.     err = PBSetCatInfo(&fpb, false);
  949.     return err;
  950. } /* SetFinderInfo() */
  951. /*
  952. ** Scan the extra fields in extra_field, and look for a MacOS EF; return a
  953. ** pointer to that EF, or NULL if it's not there.
  954. */
  955. static uch *scanMacOSexfield(uch *ef_ptr, unsigned ef_len,
  956.                              short *MacZipMode)
  957. {
  958.     while (ef_ptr != NULL && ef_len >= EB_HEADSIZE) {
  959.         unsigned eb_id  = makeword(EB_ID  + ef_ptr);
  960.         unsigned eb_len = makeword(EB_LEN + ef_ptr);
  961.         if (eb_len > (ef_len - EB_HEADSIZE)) {
  962.             Trace((stderr,
  963.               "scanMacOSexfield: block length %u > rest ef_size %un", eb_len,
  964.               ef_len - EB_HEADSIZE));
  965.             break;
  966.         }
  967.         if (isMacOSexfield(eb_id, eb_len, MacZipMode)) {
  968.             return ef_ptr;
  969.         }
  970.         ef_ptr += (eb_len + EB_HEADSIZE);
  971.         ef_len -= (eb_len + EB_HEADSIZE);
  972.     }
  973.     return NULL;
  974. }
  975. static Boolean isMacOSexfield(unsigned id, unsigned size, short *MacZipMode)
  976. {
  977.     switch (id)
  978.         {
  979.         case EF_ZIPIT:
  980.         case EF_ZIPIT2:
  981.             {               /* we do not support ZipIt's format completly  */
  982.             Info(slide, 0x221, ((char *)slide,
  983.               "warning: found %s ZipIt extra field (size %u) -> "
  984.               "file is probably not usable!!n",
  985.               (id == EF_ZIPIT2 ? "short": "long", size)));
  986.             IgnoreEF_Macfilename = true;
  987.             return false;
  988.             }
  989.         case EF_MAC3:
  990.             {
  991.             *MacZipMode = NewZipMode_EF;
  992.             IgnoreEF_Macfilename = false;
  993.             return true;
  994.             }
  995.         case EF_JLMAC:
  996.             {
  997.             *MacZipMode = JohnnyLee_EF;
  998.             IgnoreEF_Macfilename = true;
  999.             return true;
  1000.             }
  1001.         default:
  1002.             {
  1003.             *MacZipMode = UnKnown_EF;
  1004.             IgnoreEF_Macfilename = true;
  1005.             return false;
  1006.             }
  1007.         }
  1008.     return false;
  1009. }
  1010. /*
  1011. ** Return a unsigned long from a four-byte sequence
  1012. ** in big endian format
  1013. */
  1014. ulg makePPClong(ZCONST uch *sig)
  1015. {
  1016.     return (((ulg)sig[0]) << 24)
  1017.          + (((ulg)sig[1]) << 16)
  1018.          + (((ulg)sig[2]) << 8)
  1019.          +  ((ulg)sig[3]);
  1020. }
  1021. /*
  1022. ** Return a unsigned short from a two-byte sequence
  1023. ** in big endian format
  1024. */
  1025. ush makePPCword(ZCONST uch *b)
  1026. {
  1027.     return (ush)((b[0] << 8) | b[1]);
  1028. }
  1029. /*
  1030. ** Print mac extra-field
  1031. **
  1032. */
  1033. static void PrintMacExtraInfo(void)
  1034. {
  1035. #define MY_FNDRINFO fpb.hFileInfo.ioFlFndrInfo
  1036.     DateTimeRec  MacTime;
  1037.     static ZCONST char space[] = "                                    ";
  1038.     static ZCONST char line[]  = "------------------------------------"
  1039.                                  "------------------------------";
  1040.     printf("nn%s", line);
  1041.     printf("nFullPath      = [%s]", newExtraField.FullPath);
  1042.     printf("nFinderComment = [%s]", newExtraField.FinderComment);
  1043.     printf("nText Encoding Base (Filename)       "%s" n",
  1044.         PrintTextEncoding(newExtraField.fpb.hFileInfo.ioFlXFndrInfo.fdScript));
  1045.     printf("nExtraField Flags :                  %s  0x%x  %4d",
  1046.         sBit2Str(newExtraField.flags), newExtraField.flags,
  1047.         newExtraField.flags);
  1048.     printf("n%sExtra Field is %s", space,
  1049.            (newExtraField.flags & EB_M3_FL_UNCMPR ?
  1050.             "Uncompressed" : "Compressed"));
  1051.     printf("n%sFile Dates are in %u Bit", space,
  1052.            (newExtraField.flags & EB_M3_FL_TIME64 ? 64 : 32));
  1053.     printf("n%sFile UTC time adjustments are %ssupported", space,
  1054.            (newExtraField.flags & EB_M3_FL_NOUTC ? "not " : ""));
  1055.     printf("n%sFile Name is %schanged", space,
  1056.            (newExtraField.flags & EB_M3_FL_NOCHANGE ? "not " : ""));
  1057.     printf("n%sFile is a %sn", space,
  1058.            (newExtraField.flags & EB_M3_FL_DATFRK ?
  1059.             "Datafork" : "Resourcefork"));
  1060.     /* not all type / creator codes are printable */
  1061.     if (isprint((char)(newExtraField.MY_FNDRINFO.fdType >> 24)) &&
  1062.         isprint((char)(newExtraField.MY_FNDRINFO.fdType >> 16)) &&
  1063.         isprint((char)(newExtraField.MY_FNDRINFO.fdType >> 8)) &&
  1064.         isprint((char)newExtraField.MY_FNDRINFO.fdType))
  1065.     {
  1066.         printf("nFile Type =                         [%c%c%c%c]  0x%lx",
  1067.             (char)(newExtraField.MY_FNDRINFO.fdType >> 24),
  1068.             (char)(newExtraField.MY_FNDRINFO.fdType >> 16),
  1069.             (char)(newExtraField.MY_FNDRINFO.fdType >> 8),
  1070.             (char)(newExtraField.MY_FNDRINFO.fdType),
  1071.             newExtraField.MY_FNDRINFO.fdType);
  1072.     }
  1073.     else
  1074.     {
  1075.         printf("nFile Type =                                     0x%lx",
  1076.             newExtraField.MY_FNDRINFO.fdType);
  1077.     }
  1078.     if (isprint((char)(newExtraField.MY_FNDRINFO.fdCreator >> 24)) &&
  1079.         isprint((char)(newExtraField.MY_FNDRINFO.fdCreator >> 16)) &&
  1080.         isprint((char)(newExtraField.MY_FNDRINFO.fdCreator >> 8)) &&
  1081.         isprint((char)newExtraField.MY_FNDRINFO.fdCreator))
  1082.     {
  1083.         printf("nFile Creator =                      [%c%c%c%c]  0x%lx",
  1084.             (char)(newExtraField.MY_FNDRINFO.fdCreator >> 24),
  1085.             (char)(newExtraField.MY_FNDRINFO.fdCreator >> 16),
  1086.             (char)(newExtraField.MY_FNDRINFO.fdCreator >> 8),
  1087.             (char)(newExtraField.MY_FNDRINFO.fdCreator),
  1088.             newExtraField.MY_FNDRINFO.fdCreator);
  1089.     }
  1090.     else
  1091.     {
  1092.         printf("nFile Creator =                                  0x%lx",
  1093.             newExtraField.MY_FNDRINFO.fdCreator);
  1094.     }
  1095.     printf("nnDates (local time of archiving location):");
  1096.     SecondsToDate(newExtraField.fpb.hFileInfo.ioFlCrDat, &MacTime);
  1097.     printf("n    Created  =                      %4d/%2d/%2d %2d:%2d:%2d  ",
  1098.            MacTime.year, MacTime.month, MacTime.day,
  1099.            MacTime.hour, MacTime.minute, MacTime.second);
  1100.     SecondsToDate(newExtraField.fpb.hFileInfo.ioFlMdDat, &MacTime);
  1101.     printf("n    Modified =                      %4d/%2d/%2d %2d:%2d:%2d  ",
  1102.            MacTime.year, MacTime.month, MacTime.day,
  1103.            MacTime.hour, MacTime.minute, MacTime.second);
  1104.     SecondsToDate(newExtraField.fpb.hFileInfo.ioFlBkDat, &MacTime);
  1105.     printf("n    Backup   =                      %4d/%2d/%2d %2d:%2d:%2d  ",
  1106.         MacTime.year, MacTime.month, MacTime.day,
  1107.         MacTime.hour, MacTime.minute, MacTime.second);
  1108.     if (!(newExtraField.flags & EB_M3_FL_NOUTC)) {
  1109.         printf("nGMT Offset of Creation time  =      %4ld sec  %2d h",
  1110.           newExtraField.Cr_UTCoffs, (int)newExtraField.Cr_UTCoffs / (60 * 60));
  1111.         printf("nGMT Offset of Modification time  =  %4ld sec  %2d h",
  1112.           newExtraField.Md_UTCoffs, (int)newExtraField.Md_UTCoffs / (60 * 60));
  1113.         printf("nGMT Offset of Backup time  =        %4ld sec  %2d h",
  1114.           newExtraField.Bk_UTCoffs, (int)newExtraField.Bk_UTCoffs / (60 * 60));
  1115.     }
  1116.     printf("nnFinder Flags :                      %s  0x%x  %4d",
  1117.         sBit2Str(newExtraField.MY_FNDRINFO.fdFlags),
  1118.         newExtraField.MY_FNDRINFO.fdFlags,
  1119.         newExtraField.MY_FNDRINFO.fdFlags);
  1120.     printf("nFinder Icon Position =              X: %4d",
  1121.         newExtraField.MY_FNDRINFO.fdLocation.h);
  1122.     printf("n                                    Y: %4d",
  1123.         newExtraField.MY_FNDRINFO.fdLocation.v);
  1124.     printf("nnText Encoding Base (System/MacZip)  "%s"",
  1125.         PrintTextEncoding(newExtraField.TextEncodingBase));
  1126.     printf("n%s", line);
  1127. #undef MY_FNDRINFO
  1128. }
  1129. /*
  1130. ** Decode mac extra-field and assign the data to the structure
  1131. **
  1132. */
  1133. static Boolean GetExtraFieldData(short *MacZipMode, MACINFO *mi)
  1134. {
  1135. uch *ptr;
  1136. uch *attrbuff  = NULL;
  1137. int  retval = PK_OK;
  1138. Boolean MallocWasUsed = false;
  1139. ptr = scanMacOSexfield(G.extra_field, G.lrec.extra_field_length, MacZipMode);
  1140. /* MacOS is no preemptive OS therefore do some (small) event-handling */
  1141. UserStop();
  1142. if (uO.J_flag) {
  1143.     *MacZipMode = UnKnown_EF;
  1144.     IgnoreEF_Macfilename = true;
  1145.     return false;
  1146. }
  1147. if (ptr != NULL)
  1148. {
  1149.       /*   Collect the data from the extra field buffer. */
  1150.     mi->header    = makeword(ptr);    ptr += 2;
  1151.     mi->data      = makeword(ptr);    ptr += 2;
  1152.     switch (*MacZipMode)
  1153.         {
  1154.         case NewZipMode_EF:
  1155.           {
  1156.             mi->size      =  makelong(ptr); ptr += 4;
  1157.             mi->flags     =  makeword(ptr); ptr += 2;
  1158.             /* Type/Creator are always uncompressed */
  1159.             mi->fpb.hFileInfo.ioFlFndrInfo.fdType    = makePPClong(ptr);
  1160.             ptr += 4;
  1161.             mi->fpb.hFileInfo.ioFlFndrInfo.fdCreator = makePPClong(ptr);
  1162.             ptr += 4;
  1163.             if (!(mi->flags & EB_M3_FL_UNCMPR)) {
  1164.                  /* compressed extra field is not yet tested,
  1165.                     therefore it's currently not used by default */
  1166.                 attrbuff = (uch *)malloc(mi->size);
  1167.                 if (attrbuff == NULL) {
  1168.                     /* No memory to uncompress attributes */
  1169.                     Info(slide, 0x201, ((char *)slide,
  1170.                          "Can't allocate memory to uncompress file "
  1171.                          "attributes.n"));
  1172.                     *MacZipMode = UnKnown_EF;
  1173.                             /* EF-Block is unusable, ignore it */
  1174.                     return false;
  1175.                 }
  1176.                 else MallocWasUsed = true;
  1177.                 retval = memextract(__G__ attrbuff, mi->size, ptr,
  1178.                                     mi->data - EB_MAC3_HLEN);
  1179.                 if (retval != PK_OK) {
  1180.                     /* error uncompressing attributes */
  1181.                     Info(slide, 0x201, ((char *)slide,
  1182.                          "Error uncompressing file attributes.n"));
  1183.                     free(attrbuff);
  1184.                     *MacZipMode = UnKnown_EF;
  1185.                             /* EF-Block unusable, ignore it */
  1186.                     return false;
  1187.                 }
  1188.             } else {            /* file attributes are uncompressed */
  1189.                 attrbuff = ptr;
  1190.             }
  1191.             DecodeMac3ExtraField(attrbuff, mi);
  1192.             if (MallocWasUsed) free(attrbuff);
  1193.             return true;
  1194.             break;
  1195.           }
  1196.         case JohnnyLee_EF:
  1197.           {
  1198.             if (strncmp((char *)ptr, "JLEE", 4) == 0) {
  1199.                 /* Johnny Lee's old MacZip e.f. was found */
  1200.                 attrbuff  = ptr + 4;
  1201.                 DecodeJLEEextraField(attrbuff, mi);
  1202.                 return true;
  1203.             } else {
  1204.                 /* second signature did not match, ignore EF block */
  1205.                 *MacZipMode = UnKnown_EF;
  1206.                 return false;
  1207.             }
  1208.             break;
  1209.           }
  1210.         default:
  1211.           {  /* just to make sure */
  1212.             *MacZipMode = UnKnown_EF;
  1213.             IgnoreEF_Macfilename = true;
  1214.             return false;
  1215.             break;
  1216.           }
  1217.         }
  1218. }  /* if (ptr != NULL)  */
  1219. /* no Mac extra field was found */
  1220. return false;
  1221. }
  1222. /*
  1223. ** Assign the new Mac3 Extra-Field to the structure
  1224. **
  1225. */
  1226. static void DecodeMac3ExtraField(ZCONST uch *buff, MACINFO *mi)
  1227. {               /* extra-field info of the new MacZip implementation */
  1228.                 /* compresssed extra-field starts here (if compressed) */
  1229. mi->fpb.hFileInfo.ioFlFndrInfo.fdFlags      =  makeword(buff); buff += 2;
  1230. mi->fpb.hFileInfo.ioFlFndrInfo.fdLocation.v =  makeword(buff); buff += 2;
  1231. mi->fpb.hFileInfo.ioFlFndrInfo.fdLocation.h =  makeword(buff); buff += 2;
  1232. mi->fpb.hFileInfo.ioFlFndrInfo.fdFldr       =  makeword(buff); buff += 2;
  1233. mi->fpb.hFileInfo.ioFlXFndrInfo.fdIconID    =  makeword(buff); buff += 2;
  1234. mi->fpb.hFileInfo.ioFlXFndrInfo.fdUnused[0] =  makeword(buff); buff += 2;
  1235. mi->fpb.hFileInfo.ioFlXFndrInfo.fdUnused[1] =  makeword(buff); buff += 2;
  1236. mi->fpb.hFileInfo.ioFlXFndrInfo.fdUnused[2] =  makeword(buff); buff += 2;
  1237. mi->fpb.hFileInfo.ioFlXFndrInfo.fdScript    = *buff;           buff += 1;
  1238. mi->fpb.hFileInfo.ioFlXFndrInfo.fdXFlags    = *buff;           buff += 1;
  1239. mi->fpb.hFileInfo.ioFlXFndrInfo.fdComment   =  makeword(buff); buff += 2;
  1240. mi->fpb.hFileInfo.ioFlXFndrInfo.fdPutAway   =  makelong(buff); buff += 4;
  1241. mi->fpb.hFileInfo.ioFVersNum                = *buff;           buff += 1;
  1242. mi->fpb.hFileInfo.ioACUser                  = *buff;           buff += 1;
  1243. if (mi->flags & EB_M3_FL_TIME64) {
  1244.     Info(slide, 0x201, ((char *)slide,
  1245.          "Don't support 64 bit Timevalues; get a newer version of MacZip n"));
  1246.     UseUT_ExtraField = true;
  1247.     buff += 24; /* jump over the date values */
  1248. } else {
  1249.     UseUT_ExtraField = false;
  1250.     mi->fpb.hFileInfo.ioFlCrDat   =  makelong(buff); buff += 4;
  1251.     mi->fpb.hFileInfo.ioFlMdDat   =  makelong(buff); buff += 4;
  1252.     mi->fpb.hFileInfo.ioFlBkDat   =  makelong(buff); buff += 4;
  1253. }
  1254. if (!(mi->flags & EB_M3_FL_NOUTC))  {
  1255.     mi->Cr_UTCoffs =  makelong(buff); buff += 4;
  1256.     mi->Md_UTCoffs =  makelong(buff); buff += 4;
  1257.     mi->Bk_UTCoffs =  makelong(buff); buff += 4;
  1258. }
  1259. /* TextEncodingBase type & values */
  1260. /* (values 0-32 correspond to the Script Codes defined in "Inside Macintosh",
  1261.     Text pages 6-52 and 6-53) */
  1262. mi->TextEncodingBase =  makeword(buff); buff += 2;
  1263. if (mi->TextEncodingBase >= kTextEncodingUnicodeV1_1)  {
  1264.     Info(slide, 0x201, ((char *)slide,
  1265.          "Don't support Unicoded Filenames; get a newer version of MacZipn"));
  1266.     IgnoreEF_Macfilename = true;
  1267. }
  1268. mi->FullPath      = (char *)buff; buff += strlen(mi->FullPath) + 1;
  1269. mi->FinderComment = (char *)buff; buff += strlen(mi->FinderComment) + 1;
  1270. if (uO.i_flag) IgnoreEF_Macfilename = true;
  1271. }
  1272. /*
  1273. ** Assign the new JLEE Extra-Field to the structure
  1274. **
  1275. */
  1276. static void DecodeJLEEextraField(ZCONST uch *buff, MACINFO *mi)
  1277. { /*  extra-field info of Johnny Lee's old MacZip  */
  1278. mi->fpb.hFileInfo.ioFlFndrInfo.fdType       = makePPClong(buff); buff += 4;
  1279. mi->fpb.hFileInfo.ioFlFndrInfo.fdCreator    = makePPClong(buff); buff += 4;
  1280. mi->fpb.hFileInfo.ioFlFndrInfo.fdFlags      = makePPCword(buff); buff += 2;
  1281. mi->fpb.hFileInfo.ioFlFndrInfo.fdLocation.v = makePPCword(buff); buff += 2;
  1282. mi->fpb.hFileInfo.ioFlFndrInfo.fdLocation.h = makePPCword(buff); buff += 2;
  1283. mi->fpb.hFileInfo.ioFlFndrInfo.fdFldr       = makePPCword(buff); buff += 2;
  1284. mi->fpb.hFileInfo.ioFlCrDat                =  makePPClong(buff); buff += 4;
  1285. mi->fpb.hFileInfo.ioFlMdDat                =  makePPClong(buff); buff += 4;
  1286. mi->flags                                  =  makePPClong(buff); buff += 4;
  1287.      /* scriptTag isn't stored in Johnny Lee's ef definiton */
  1288. newExtraField.fpb.hFileInfo.ioFlXFndrInfo.fdScript = smRoman;
  1289. }
  1290. /*
  1291. ** Return char* to describe the text encoding
  1292. **
  1293. */
  1294. static char *PrintTextEncoding(short script)
  1295. {
  1296. char *info;
  1297. static char buffer[14];
  1298. /* TextEncodingBase type & values */
  1299. /* (values 0-32 correspond to the Script Codes defined in
  1300.    Inside Macintosh: Text pages 6-52 and 6-53 */
  1301. switch (script) {               /* Mac OS encodings*/
  1302.     case kTextEncodingMacRoman:         info = "Roman";             break;
  1303.     case kTextEncodingMacJapanese:      info = "Japanese";          break;
  1304.     case kTextEncodingMacChineseTrad:   info = "ChineseTrad";       break;
  1305.     case kTextEncodingMacKorean:        info = "Korean";            break;
  1306.     case kTextEncodingMacArabic:        info = "Arabic";            break;
  1307.     case kTextEncodingMacHebrew:        info = "Hebrew";            break;
  1308.     case kTextEncodingMacGreek:         info = "Greek";             break;
  1309.     case kTextEncodingMacCyrillic:      info = "Cyrillic";          break;
  1310.     case kTextEncodingMacDevanagari:    info = "Devanagari";        break;
  1311.     case kTextEncodingMacGurmukhi:      info = "Gurmukhi";          break;
  1312.     case kTextEncodingMacGujarati:      info = "Gujarati";          break;
  1313.     case kTextEncodingMacOriya:         info = "Oriya";             break;
  1314.     case kTextEncodingMacBengali:       info = "Bengali";           break;
  1315.     case kTextEncodingMacTamil:         info = "Tamil";             break;
  1316.     case kTextEncodingMacTelugu:        info = "Telugu";            break;
  1317.     case kTextEncodingMacKannada:       info = "Kannada";           break;
  1318.     case kTextEncodingMacMalayalam:     info = "Malayalam";         break;
  1319.     case kTextEncodingMacSinhalese:     info = "Sinhalese";         break;
  1320.     case kTextEncodingMacBurmese:       info = "Burmese";           break;
  1321.     case kTextEncodingMacKhmer:         info = "Khmer";             break;
  1322.     case kTextEncodingMacThai:          info = "Thai";              break;
  1323.     case kTextEncodingMacLaotian:       info = "Laotian";           break;
  1324.     case kTextEncodingMacGeorgian:      info = "Georgian";          break;
  1325.     case kTextEncodingMacArmenian:      info = "Armenian";          break;
  1326.     case kTextEncodingMacChineseSimp:   info = "ChineseSimp";       break;
  1327.     case kTextEncodingMacTibetan:       info = "Tibetan";           break;
  1328.     case kTextEncodingMacMongolian:     info = "Mongolian";         break;
  1329.     case kTextEncodingMacEthiopic:      info = "Ethiopic";          break;
  1330.     case kTextEncodingMacCentralEurRoman: info = "CentralEurRoman"; break;
  1331.     case kTextEncodingMacVietnamese:    info = "Vietnamese";        break;
  1332.     case kTextEncodingMacExtArabic:     info = "ExtArabic";         break;
  1333.     case kTextEncodingUnicodeV1_1:      info = "Unicode V 1.1";     break;
  1334.     case kTextEncodingUnicodeV2_0:      info = "Unicode V 2.0";     break;
  1335.     default:  {
  1336.         sprintf(buffer,"Code: 0x%x",(short) script);
  1337.         info = buffer;
  1338.         break;
  1339.         }
  1340.     }
  1341. return info;
  1342. }
  1343. /*
  1344. ** Init Globals
  1345. **
  1346. */
  1347. void   MacGlobalsInit(__GPRO)
  1348. {
  1349. newExtraField.FullPath      = NULL;
  1350. newExtraField.FinderComment = NULL;
  1351. firstcall_of_macopen = true;
  1352. MacZipMode = UnKnown_EF;
  1353. IgnoreEF_Macfilename = true;
  1354. }
  1355. /*
  1356. ** Convert the MacOS-Strings (Filenames/Findercomments) to a most compatible.
  1357. ** These strings will be stored in the public area of the zip-archive.
  1358. ** Every foreign platform (outside macos) will access these strings
  1359. ** for extraction.
  1360. */
  1361. static void MakeMacOS_String(char *MacOS_Str,
  1362.             const char SpcChar1, const char SpcChar2,
  1363.             const char SpcChar3, const char SpcChar4)
  1364. {
  1365.     char *tmpPtr;
  1366.     register uch curch;
  1367.     for (tmpPtr = MacOS_Str; (curch = *tmpPtr) != ''; tmpPtr++)
  1368.     {
  1369.         if (curch == SpcChar1)
  1370.             *tmpPtr = SpcChar2;
  1371.         else
  1372.         if (curch == SpcChar3)
  1373.             *tmpPtr = SpcChar4;
  1374.         else  /* default */
  1375.             if (curch > 127)
  1376.                {
  1377.                    *tmpPtr = (char)ISO8859_1_to_MacRoman[curch - 128];
  1378.                }
  1379.     }  /* end for */
  1380. }