home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Amiga / Workbench / Archivers / gguuwos.lha / gguucode.c < prev    next >
C/C++ Source or Header  |  1998-05-02  |  12KB  |  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 <clib/exec_protos.h>
  47. #include <clib/dos_protos.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.