home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Amiga / Workbench / Archivers / GGUUcode.lha / gguucode.c < prev    next >
C/C++ Source or Header  |  1998-03-14  |  9KB  |  441 lines

  1. /*
  2.  * gguucode
  3.  *
  4.  * uuencoder/decoder for Amiga 68k and PowerUP (elf binary)
  5.  *
  6.  * To compile (with SAS/C PPC):
  7.  * 
  8.  * scppc gguucode
  9.  * ppc-amigaos-ld -r -o gguucode lib:c_ppc.o gguucode.o lib:scppc.a lib:end.o
  10.  * protect gguucode +e
  11.  *
  12.  */
  13.  
  14. /* Realized by Gabriele Greco
  15.  *
  16.  * Original authors:
  17.  *
  18.  * Written by Mark Horton
  19.  * Modified by ajr (Alan J Rosenthatl,flaps@utcsri.UUCP) to use checksums
  20.  * Modified by fnf (Fred Fish,well!fnf) to use Keith Pyle's suggestion for
  21.  * compatibility
  22.  * Modified by bcn (Bryce Nesbitt,ucbvax!cogsci!bryce) to fix a misleading
  23.  * error message on the Amiga port, to fix a bug that prevented decoding
  24.  * certain files, to work even if trailing spaces have been removed from a
  25.  * file, to check the filesize (if present), to add some error checking, to
  26.  * loop for multiple decodes from a single file, and to handle common
  27.  * BITNET mangling.  Kludged around a missing string function in Aztec
  28.  * C. Changed "r" to "rb" and "w" to "wb" for Messy-dos machines
  29.  * (Thanks to Andrew Wylie).
  30.  */
  31.  
  32. #define __USE_SYSBASE
  33.  
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37.  
  38. #include <ctype.h>
  39.  
  40. #include <sys/types.h>
  41. #include <sys/stat.h>
  42. #include <sys/dir.h>
  43.  
  44. #include <exec/types.h>
  45. #include <dos/rdargs.h>
  46. #include <proto/exec.h>
  47. #include <proto/dos.h>
  48.  
  49. UBYTE __aligned version [] = "\0$VER: ggdecode 1.0 (13.3.98)";
  50.  
  51. void decode(FILE *in, FILE *out, UBYTE *dest);
  52. LONG filemode(FILE *in);
  53. void encode(FILE *in, FILE *out);
  54. LONG outdec(UBYTE *p, FILE *f);
  55. LONG fr(FILE *fd, UBYTE *buf, LONG cnt);
  56.  
  57. LONG totalsize = 0; /* Used to count the file size because ftell() does
  58.                not return sane results for pipes */
  59.  
  60. void start_encode(FILE *in,FILE *out,UBYTE *dest)
  61. {
  62.     fprintf(out,"\nbegin %o %s\n", filemode(in), FilePart(dest));
  63.  
  64.     encode(in, out);
  65.  
  66.     fprintf(out,"end\n");
  67.     fprintf(out,"size %ld\n",totalsize);
  68. }
  69.  
  70. long main(void)
  71. {
  72.  FILE *in, *out;
  73.  LONG through_loop = 0; /* Dejavu indicator */
  74.  LONG mode;        /* file's mode (from header) */
  75.  LONG filesize;            /* theoretical file size (from header) */
  76.  UBYTE dest[200],source[200];
  77.  UBYTE buf[80];
  78.  STRPTR Arg[4]={NULL,NULL,NULL,NULL};
  79.  struct RDArgs *Args;
  80.  char action=2;
  81.  
  82.     /* A filename can be specified to be uudecoded, or nothing can
  83.     be specified, and the input will come from STDIN */
  84.  
  85.  if(Args=ReadArgs("FILE,A=ENCODE/S,X=DECODE/S,TO=DEST/K",(LONG *)Arg,NULL))
  86.  {
  87. /*
  88.     int i;
  89.     for(i=0;i<4;i++)
  90.     {
  91.         printf("Arg %ld -> %ld - %s\n",i,Arg[i],Arg[i]);
  92.     }
  93. */
  94.     if(Arg[2]&&Arg[1])
  95.     {
  96.         printf("You cant encode and decode at the same time!\n");
  97.         action=0;
  98.     }
  99.     else if(Arg[1])
  100.     {
  101.         action=1;
  102.     }
  103.     else if(Arg[2])
  104.     {
  105.         action=2;
  106.     }
  107.  
  108.     if(!Arg[0])
  109.     {
  110.         if(action==2)
  111.             in=stdin;
  112.         else if(action==1)
  113.         {
  114.             printf("You can't encode from stdin!\n");
  115.             action=0;
  116.         }
  117.     }
  118.     else
  119.     {
  120.         strcpy(source,Arg[0]);
  121.  
  122.         if(!(in=fopen(Arg[0],"r")))
  123.         {
  124.             printf("Unable to open source file!\n");
  125.             action=0;
  126.         }
  127.     }
  128.  
  129.     if(Arg[3])
  130.     {
  131.         DIR *d;
  132.  
  133.         strcpy(dest,Arg[3]);
  134.  
  135.         if(out=fopen(dest,"r"))
  136.         {
  137.             printf("The output file %s already exists!\n",dest);
  138.             fclose(out);
  139.             action=0;
  140.         }
  141.         else if(dest[strlen(dest)-1]!='/'&&dest[strlen(dest)-1]!=':')
  142.         {
  143.             if(d=opendir(dest))
  144.             {
  145.                 strcat(dest,"/");
  146.  
  147.                 if(action==1)
  148.                 {
  149.                     printf("Destination must be a file if you are encoding!\n");
  150.                     action=0;
  151.                 }
  152.  
  153.                 closedir(d);
  154.             }
  155.         }
  156.         else
  157.         {
  158.             if(action==1 && (dest[strlen(dest)-1]=='/' || dest[strlen(dest)-1]==':') )
  159.             {
  160.                 printf("Destination must be a file if you are encoding!\n");
  161.                 action=0;
  162.             }
  163.         }
  164.     }
  165.     else
  166.     {
  167.         dest[0]=0;
  168.  
  169.         if(action==1)
  170.         {
  171.             out=stdout;
  172.         }
  173.     }
  174.  
  175.     FreeArgs(Args);
  176.  }
  177.  else
  178.  {
  179.     printf("Error in the command line!\n");
  180.     action=0;
  181.  }
  182.  
  183.  if(!action)
  184.  {
  185.     exit(0);
  186.  }
  187.  else if (action==1)
  188.  {
  189.     if(dest[0]!=0)
  190.         if ((out = fopen(dest, "w")) == NULL)
  191.         {
  192.         fprintf(stderr, "ERROR: can't open output file %s\n", dest);
  193.         exit(20);
  194.         }
  195.  
  196.     start_encode(in,out,source);
  197.  }
  198.  else for (;;)
  199.  {
  200.     /* search file for header line */
  201.     for (;;)
  202.     {
  203.     if (fgets(buf, sizeof buf, in) == NULL)
  204.         {
  205.         if (!through_loop)
  206.         {
  207.         fprintf(stderr, "ERROR: no `begin' line!\n");
  208.         exit(20);
  209.         }
  210.         else
  211.         {
  212.         exit(0);
  213.         }
  214.         }
  215.     if (strncmp(buf, "begin ", 6) == 0)
  216.         break;
  217.     }
  218.  
  219.     if(!dest[0])
  220.     {
  221.         sscanf(buf, "begin %o %s", &mode, dest);
  222.     }
  223.     else if(dest[strlen(dest)-1]=='/'||dest[strlen(dest)-1]==':')
  224.     {
  225.     sscanf(buf, "begin %o %s", &mode, &dest[strlen(dest)]);
  226.     }
  227.  
  228.     /* create output file */
  229.     if ((out = fopen(dest, "w")) == NULL)
  230.     {
  231.     fprintf(stderr, "ERROR: can't open output file %s\n", dest);
  232.     exit(20);
  233.     }
  234.  
  235.     decode(in, out, dest);
  236.  
  237.     if (fgets(buf, sizeof buf, in) == NULL || strncmp(buf,"end",3))
  238.     {           /* don't be overly picky about newline ^ */
  239.     fprintf(stderr, "ERROR: no `end' line\n");
  240.     exit(20);
  241.     }
  242.  
  243.     if (!(fgets(buf,sizeof buf,in) == NULL || strncmp(buf,"size ",3)))
  244.     {
  245.     sscanf(buf, "size %ld", &filesize);
  246.     if (ftell(out) != filesize)
  247.         {
  248.         fprintf(stderr, "ERROR: file should have been %ld bytes long but was %ld.\n", filesize, ftell(out));
  249.         exit(20);
  250.         }
  251.     }
  252.     through_loop = 1;
  253. }   /* forever */
  254.  
  255.  exit(0);
  256. }
  257.  
  258. #define SUMSIZE 64
  259. #define DEC(c)  (((c) - ' ') & 077)    /* single character decode */
  260.  
  261. /*
  262.  * Copy from in to out, decoding as you go.
  263.  * If a return or newline is encountered too early in a line, it is
  264.  * assumed that means that some editor has truncated trailing spaces.
  265.  */
  266. void decode(FILE *in, FILE *out, UBYTE *dest)
  267. {
  268.  extern errno;
  269.  
  270.  UBYTE *bp;
  271.  LONG nosum=0;
  272.  LONG j, n, checksum, line;
  273.  UBYTE buf[256];
  274.  
  275.     for (line = 1; ; line++)    /* for each input line */
  276.     {
  277.     if (fgets(buf, sizeof buf, in) == NULL)
  278.         {
  279.         fprintf(stderr, "ERROR: input ended unexpectedly!\n");
  280.         exit(20);
  281.         }
  282.  
  283.     /* Pad end of lines in case some editor truncated trailing
  284.        spaces */
  285.  
  286.     for (n=0;n<79;n++)  /* search for first \r, \n or \000 */
  287.         {
  288.         if (buf[n]=='\176')     /* If BITNET made a twiddle, */
  289.         buf[n]='\136';     /* we make a caret           */
  290.         if (buf[n]=='\r'||buf[n]=='\n'||buf[n]=='\000')
  291.         break;
  292.         }
  293.     for (;n<79;n++)     /* when found, fill rest of line with space */
  294.         {
  295.         buf[n]=' ';
  296.         }
  297.     buf[79]=0;        /* terminate new string */
  298.  
  299.     checksum = 0;
  300.     n = DEC(buf[0]);
  301.     if (n <= 0)
  302.         break;    /* 0 bytes on a line??    Must be the last line */
  303.  
  304.     bp = &buf[1];
  305.  
  306.     /* FOUR input characters go into each THREE output charcters */
  307.  
  308.     while (n >= 4)
  309.         {
  310.         j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4; putc(j, out); checksum += j;
  311.         j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2; putc(j, out); checksum += j;
  312.         j = DEC(bp[2]) << 6 | DEC(bp[3]);      putc(j, out); checksum += j;
  313.         checksum = checksum % SUMSIZE;
  314.         bp += 4;
  315.         n -= 3;
  316.         }
  317.  
  318.         j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4;
  319.         checksum += j;
  320.         if (n >= 1)
  321.             putc(j, out);
  322.         j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2;
  323.         checksum += j;
  324.         if (n >= 2)
  325.             putc(j, out);
  326.         j = DEC(bp[2]) << 6 | DEC(bp[3]);
  327.         checksum += j;
  328.         if (n >= 3)
  329.             putc(j, out);
  330.         checksum = checksum % SUMSIZE;
  331.         bp += 4;
  332.         n -= 3;
  333.  
  334.      /* Error checking under UNIX??? You must be kidding... */
  335.      /* Check if an error occured while writing to that last line */
  336.     if (errno)
  337.         {
  338.         fprintf(stderr, "ERROR: error writing to %s\n",dest);
  339.         exit(20);
  340.         }
  341.  
  342.     /* The line has been decoded; now check that sum */
  343.  
  344.     nosum |= !isspace(*bp);
  345.     if (nosum)                      /* Is there a checksum at all?? */
  346.         {
  347.         if (checksum != DEC(*bp))   /* Does that checksum match? */
  348.         {
  349.         fprintf(stderr, "ERROR: checksum mismatch decoding %s, line %d.\n",dest, line);
  350.         }
  351.         }    /* sum */
  352.     }    /* line */
  353. }   /* function */
  354.  
  355. LONG filemode(FILE *in)
  356. {
  357. #ifdef unix_stat
  358.     struct stat sbuf;
  359.     
  360.     fstat(fileno(in), &sbuf);
  361.     return( sbuf.st_mode & 0777); /* figure out the input file mode */
  362.  
  363. #else
  364.     return( 0644 );               /* Default permissions */
  365. #endif
  366. }
  367.  
  368. #define SUMSIZE 64  /* 6 bits */
  369. /* ENC is the basic 1 character encode function to make a char printing */
  370. /* Each output character represents 6 bits of input */
  371. #define ENC(c) ((c) ? ((c) & 077) + ' ': '`')
  372.  
  373. /*
  374.  * copy from in to out, encoding as you go along.
  375.  */
  376. void encode(FILE *in, FILE *out)
  377. {
  378.  extern errno;
  379.  
  380.     LONG i, n, checksum;
  381.     char buf[256];
  382.  
  383.     for (;;) {
  384.         /* 1 (up to) 45 character line */
  385.         n = fr(in, buf, 45);
  386.         putc(ENC(n), out);
  387.  
  388.         checksum = 0;
  389.         for (i=0; i<n; i += 3)
  390.             checksum = (checksum+outdec(&buf[i], out)) % SUMSIZE;
  391.  
  392.         putc(ENC(checksum), out);
  393.         putc('\n', out);
  394.  
  395.         /* Error checking under UNIX?? You must be kidding! */
  396. /*
  397.         if (errno) {
  398.             fprintf(stderr, "ERROR: error writing to output\n");
  399.             exit(20);
  400.             }
  401. */
  402.         if (n <= 0)
  403.             break;
  404.     }
  405. }
  406.  
  407. /*
  408.  * output one group of 3 bytes, pointed at by p, on file f.
  409.  * return the checksum increment.
  410.  */
  411. LONG outdec(UBYTE *p, FILE *f)
  412. {
  413.     LONG c1, c2, c3, c4;
  414.  
  415.     c1 = *p >> 2;
  416.     c2 = (*p << 4) & 060 | (p[1] >> 4) & 017;
  417.     c3 = (p[1] << 2) & 074 | (p[2] >> 6) & 03;
  418.     c4 = p[2] & 077;
  419.     putc(ENC(c1), f);
  420.     putc(ENC(c2), f);
  421.     putc(ENC(c3), f);
  422.     putc(ENC(c4), f);
  423.  
  424.     return((p[0]+p[1]+p[2]) % SUMSIZE);
  425. }
  426.  
  427. /* fr: like read but stdio */
  428. LONG fr(FILE *fd, UBYTE *buf, LONG cnt)
  429. {
  430.     LONG c, i;
  431.  
  432.     for (i=0; i<cnt; i++) {
  433.         c = getc(fd);
  434.         if (c == EOF)
  435.             return(i);
  436.         totalsize++;
  437.         buf[i] = c;
  438.     }
  439.     return (cnt);
  440. }
  441.