This is uudecode.c in view mode; [Download] [Up]
/* $Id: uudecode.c,v 1.1.1.1 1996/01/31 13:44:34 alex Exp $ * * $Log: uudecode.c,v $ * Revision 1.1.1.1 1996/01/31 13:44:34 alex * Importierte Source, Version 0.82 von Constantin * * Revision 4.4 1991/09/09 20:27:37 sob * release 4.4 * * Altered to work with NeXT's NXStreams. * Altering done by Todd Thomas, July 4, 1995. * * Decode one or more uuencoded articles back to binary form. * Adapted to rn 4.4 by Stan Barber * Trn version created by Wayne Davison. * Adapted from the nn version by Kim Storm. * From the Berkeley original, modified by MSD, RDR, JPHD & WLS. */ /* * This software is Copyright 1991 by Stan Barber. * * Permission is hereby granted to copy, reproduce, redistribute or otherwise * use this software as long as: there is no monetary profit gained * specifically from the use or reproduction of this software, it is not * sold, rented, traded or otherwise marketed, and this copyright notice is * included prominently in any copy made. * * The author make no claims as to the fitness or correctness of this software * for any use whatsoever, and it is provided as is. Any use of this software * is at the user's own risk. */ #include <sys/param.h> #include <string.h> #include <libc.h> #include <stdlib.h> #include <ctype.h> //#include "EXTERN.h" //#include "common.h" //#include "respond.h" #include "decode.h" #define MAXCHAR 256 #define NORMLEN 64 /* allows for 84 encoded chars per line */ #define SEQMAX 'z' #define SEQMIN 'a' #define strNE(s1,s2) (strcmp(s1,s2)) #define strEQ(s1,s2) (!strcmp(s1,s2)) #define strnNE(s1,s2,l) (strncmp(s1,s2,l)) #define strnEQ(s1,s2,l) (!strncmp(s1,s2,l)) /* Forward declarations */ static int decode_line (char *); static void inittbls (void); static void gettable (NXStream *in); static char* NXgets (char *buf, long buflen, NXStream *theStream); // static void decode_end(); /* Some declarations that were in decode.h */ static FILE* decode_fp = NULL; static char decode_fname[MAXPATHLEN+1]; static char decode_dest[MAXPATHLEN+1]; /* Temporary */ static char *extractdest = NULL; static char seqc; static int first, secnd, check, numl; static char blank; static int chtbl[MAXCHAR], cdlen[NORMLEN + 3]; static int state; static BOOL Xflag; static int expecting_part; const char* decodeDepositPathname() { if(!extractdest) return "\tmp"; return extractdest; } void setDecodeDepositPathname(const char* aPathname) { if (aPathname){ if(extractdest) free (extractdest); extractdest=malloc((strlen(aPathname)+2)*sizeof(char)); strcpy(extractdest, aPathname); } } void uud_start() { Xflag = FALSE; expecting_part = 0; seqc = SEQMAX; check = 1; first = 1; secnd = 0; state = FIND_BEGIN; decode_fp = NULL; } // This is a hack because you can't tell if uudecode failed when // you only expect a single part. If it doesn't find the "end" // it assumes that it is continued and returns success. This way we // can look into the state after a uudecode to see what it's last // state was. int uudecode_state() { return state; } int uudecode(NXStream *in) { int mode, onedone, lens; char buff[LBUFLEN]; numl = onedone = 0; if (state == FIND_BEGIN) inittbls(); /* * search for header or translation table line. */ while ((state & NO_ADVANCE) || NXgets(buff, sizeof buff, in) != Nullch) { numl++; switch (state) { case NEW_BEGIN: if (decode_fp != Nullfp) { if (expecting_part) { register int got_part = 0; if (strnEQ(buff + 6, "part ", 5)) { register char *bp; for (bp = buff + 11; islower(*bp); bp++) got_part = got_part * 26 + *bp - 'a'; } if (expecting_part == got_part) { state = DECODE_TEXT; break; } printf("Expecting part %d; got part %d.\n", expecting_part + 1, got_part + 1); if (got_part) { state = SKIP_LEADING; return -1; } } decode_end(); sleep(2); Xflag = FALSE; expecting_part = 0; } state = FIND_BEGIN; /* fall thru */ case FIND_BEGIN: case AFTER_ERROR_FIND_BEGIN: if (strnEQ(buff, "table", 5)) { gettable(in); continue; } if (strnEQ(buff, "begin ", 6) || strnEQ(buff, "Xbegin ", 7)) { lens = strlen(buff)-1; if (buff[lens] == '\n') buff[lens] = '\0'; if(sscanf(buff+6,"%o%s", &mode, decode_fname) != 2) { register char *bp = buff + 6; if (*bp == ' ') bp++; if (strnEQ(bp, "part ", 5)) { register int got_part = 0; for (bp = bp + 5; islower(*bp); bp++) got_part = got_part * 26 + *bp - 'a'; printf("Expecting part 1; got part %d.\n", got_part + 1); return -1; } continue; } Xflag = (*buff == 'X'); sprintf(decode_dest, "%s/%s",decodeDepositPathname(), decode_fname); if ((decode_fp = fopen(decode_dest, FOPEN_WB)) == Nullfp) { printf("Cannot create file: %s\n", decode_dest); goto err; } chmod(decode_dest, mode); printf("Decoding: %s\n", decode_fname); state = DECODE_TEXT; } continue; case SKIP_LEADING: state = decode_line(buff); continue; case DECODE_TEXT: state = decode_line(buff); onedone = 1; continue; case FOUND_END: fclose(decode_fp); decode_fp = Nullfp; Xflag = FALSE; expecting_part = 0; state = FIND_BEGIN; printf("Done.\n"); continue; case SKIP_TRAILING: printf("(Continued)\n"); state = SKIP_LEADING; return 0; case DECODE_ERROR: state = SKIP_TRAILING; continue; case OTHER_ERROR: fclose(decode_fp); decode_fp = Nullfp; Xflag = FALSE; expecting_part = 0; state = AFTER_ERROR_FIND_BEGIN; goto err; } } if (onedone) { if (state == DECODE_TEXT) { printf("(Continued)\n"); state = SKIP_LEADING; } return 0; } if (state == AFTER_ERROR_FIND_BEGIN) return -1; printf("Couldn't find anything to decode.\n"); err: sleep(2); return -1; } /* * decode one line and write it out using decode_fp */ static int decode_line(char *buff) { char outl[LBUFLEN]; register char *bp, *ut; register int *trtbl = chtbl; register int n; register int blen; /* binary length (from decoded file) */ register int rlen; /* calculated input line length */ register int len; /* actual input line length */ register int dash; /* number of '-'s encountered on a line */ /* If it's too high, we reject the line */ # define REJECT(buf,rlen,len) /* Comment for makedepend to \ ** ignore the backslash above */ \ ((*buf == 'M' && len > rlen + 5) \ || (*buf != 'M' && len != rlen && len != rlen+1) \ || (strnEQ(buf, "BEGIN", 5)) \ || (strnEQ(buf, "END", 3))) if (Xflag) { if (*buff == 'X') buff++; else *buff = 'x'; /* force a mis-parse of a non-x'ed line */ } len = strlen(buff); if (--len <= 0) return state; buff[len] = '\0'; /* * Get the binary line length. */ if ((blen = trtbl[buff[0]]) < 0) { if (state == SKIP_LEADING) { if (strnEQ(buff, "begin ", 6)) return NEW_BEGIN; return SKIP_LEADING; } /* * end of uuencoded file ? */ if (strnEQ(buff, "end", 3)) return FOUND_END; /* * end of current file ? : get next one. */ if (strnEQ(buff, "include ", 8)) { for (bp = buff + 8; *bp; bp++) { if (bp[0] == '.' && bp[1] == 'u') { expecting_part = (bp[2] - 'a') * 26 + bp[3] - 'a'; break; } } } /* * trailing garbage */ return SKIP_TRAILING; } rlen = cdlen[blen]; if (state == SKIP_LEADING && REJECT(buff,rlen,len)) return SKIP_LEADING; /* * Is it the empty line before the end line ? */ if (blen == 0) return state; if (REJECT(buff,rlen,len)) return SKIP_TRAILING; /* * Pad with blanks. */ for (bp = buff + len, n = rlen - len; --n >= 0; ) *bp++ = blank; /* * Verify */ for (n = rlen, bp = buff, dash = 0; --n >= 0; bp++) { if (trtbl[*bp] < 0) { if (state == SKIP_LEADING) return SKIP_LEADING; return DECODE_ERROR; } if (*bp == '-') dash++; } if (dash * 100 / rlen > 33) /* more than 1/3 dashes? */ if (state == SKIP_LEADING) return SKIP_LEADING; /* -> reject */ else return SKIP_TRAILING; /* * Check for uuencodes that append a 'z' to each line.... */ if (check) if (secnd) { secnd = 0; if (buff[rlen] == SEQMAX) check = 0; } else if (first) { first = 0; secnd = 1; if (buff[rlen] != SEQMAX) check = 0; } /* * There we check. */ if (check) { if (buff[rlen] != seqc) { if (state == SKIP_LEADING) return SKIP_LEADING; return DECODE_ERROR; } if (--seqc < SEQMIN) seqc = SEQMAX; } /* * output a group of 3 bytes (4 input characters). * the input chars are pointed to by p, they are to * be output to file f. blen is used to tell us not to * output all of them at the end of the file. */ ut = outl; n = blen; bp = &buff[1]; while (--n >= 0) { *(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4; if (n > 0) { *(ut++) = (trtbl[bp[1]] << 4) | (trtbl[bp[2]] >> 2); n--; } if (n > 0) { *(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]]; n--; } bp += 4; } if (fwrite(outl, 1, blen, decode_fp) <= 0) { printf("Error on writing decoded file\n"); return OTHER_ERROR; } return DECODE_TEXT; } /* * Install the table in memory for later use. */ static void inittbls() { register int i, j; /* * Set up the default translation table. */ for (i = 0; i < ' '; i++) chtbl[i] = -1; for (i = ' ', j = 0; i < ' ' + 64; i++, j++) chtbl[i] = j; for (i = ' ' + 64; i < MAXCHAR; i++) chtbl[i] = -1; chtbl['`'] = chtbl[' ']; /* common mutation */ chtbl['~'] = chtbl['^']; /* another common mutation */ blank = ' '; /* * set up the line length table, to avoid computing lotsa * and / ... */ cdlen[0] = 1; for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4) cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j)); } static void gettable(NXStream *in) { char buff[LBUFLEN]; register int c, n = 0; register char *cpt; for (c = 0; c < MAXCHAR; c++) chtbl[c] = -1; for (;;) { if (NXgets(buff, sizeof buff, in) == Nullch) { printf("EOF while in translation table.\n"); return; } numl++; if (strnEQ(buff, "begin", 5)) { printf("Incomplete translation table.\n"); return; } cpt = buff + strlen(buff) - 1; *cpt = ' '; while (*cpt == ' ') { *cpt = 0; cpt--; } cpt = buff; while (c = *cpt) { if (chtbl[c] != -1) { printf("Duplicate char in translation table.\n"); return; } if (n == 0) blank = c; chtbl[c] = n++; if (n >= 64) return; cpt++; } } } char* NXgets (char *buf, long buflen, NXStream *theStream) { /* Simulates fgets using NXStreams. Takes the same types of args and returns the same values. */ int bWritten; char inChar; if (!buf || buflen < 1) { return NULL; } bWritten = 0; inChar = '\0'; memset(buf, 0, buflen); // while (!NXAtEOS(theStream) && ((inChar = NXGetc(theStream)) != '\n') && // (inChar != EOF)) { while (!NXAtEOS(theStream) && (inChar != EOF)) { inChar = NXGetc(theStream); if (bWritten == buflen-1) { return buf; } *(buf+bWritten) = inChar; bWritten++; if (inChar == '\n') { break; } } return (!NXAtEOS(theStream)) ? buf : NULL; } void decode_end() { if (decode_fp != Nullfp) { fclose(decode_fp); decode_fp = Nullfp; printf("\n%s INCOMPLETE -- removed.\n", decode_dest); unlink(decode_dest); } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.