/* UNBCODE: bcode decoder program version 2.02 by Craig Bruce, 28-Feb-1995. ** ** This program decodes binary data from BCODE, NUCODE, UUCODE, and ** HEXCODE formats. ** ** usage: unbcode [-ivdnf] [-p prefix] [filename ...] ** ** -i : "informative" mode: tells you when files are recombined ** -v : verbose mode: tells you what it is up to ** -d : debugging mode: tells you about the file fragments it is juggling ** -n : spits out names (only) of files extracted and recombined ** -f : force: ignores decoding errors ** -p : give filename prefix for temporary files ** -help : gives usage information ** ** CRC-32 code based on "File Verification Using CRC" by Mark R. Nelson in ** Dr. Dobb's Journal, May 1992, pp. 64-67. Note that CRC-32 values ARE the ** same as in ZMODEM and PKZIP. ** ** v1.00: Original release, in K&R C. 07-Oct-1993. ** v1.01: Fixed some printf formats. 09-Oct-1993. ** v1.02: Added code for remove and rename. To activate, add -DNO_REMOVE ** and/or -DNO_RENAME as needed. 15-Oct-1993, done by B.J.S. ** v1.03: Fixed some more printf formats. 09-Nov-1993. ** v1.04: Replaced CRC constants table by generating function. 30-Jan-1994. ** v1.05: Included functionality of "nu-decode", improved uudecoder. ** v1.06: Added flag for ignoring errors, recovers fully from partial data ** of invalid decodes. ** v1.07: Added support for "hexcode" encoding format. 29-Apr-1994. ** v1.08: Fixed bug of not scanning first line after a uuencoded segment's ** "end" token. 26-May-1994. ** v1.09: Made it accept segment separators of the form "-bcode-begin" ** (with one hyphen) for compatibility with anonymous mail/post ** servers which erase everything following a line that starts with ** two hyphens. Also accepts string "nocrcxxx" in place of a ** hexadecimal crc-32 value to make fewer requirements on bcode ** encoder/filter programs. 16-Nov-1994. ** v1.10: Added a "prefix" option to allow you to keep the intermediate ** temporary files generated during decoding in a separate directory. ** Note that this is a prefix rather than a directory name, so you ** will have to include the final slash character in the prefix ** name on a Unix system. Note that using this option means that the ** final intermediate reassembled file will have to be copied rather ** than renamed to the final filename. Also made the program accept ** the segment length of zero as meaning "don't care" to make fewer ** requirements on filter programs. Also converted program back to ** ANSI C. 05-Dec-1994. ** v2.00: Tested and made some cosmetic changes, prepared for big release. ** 05-Dec-1994. ** v2.01: Arrggh! I found out that sscanf on a "%s" stops scanning at the ** first whitespace character: filenames with spaces were not handled ** correctly; fixed. 27-Feb-1995. ** v2.02: D'ooh! v2.01 introduced a bug into decoding regular uuencoded ** files; fixed. Fixed a couple of printf formats too. 28-Feb-1995. */ #include #include #include /*#include */ /*use this plus -DNO_RENAME -DNO_REMOVE some systems*/ #define VERSION "2.01" #define MAX_CHUNK 64 #define MAX_LINE 90 #define MAX_FILENAME 127 #define MAX_TEMPNAME 20 #define MAX_FRAG 1024 #define COPY_BUF_SIZE 4096 #define BCODE 1 #define UUCODE 2 #define HEXCODE 3 #ifdef NO_REMOVE #define remove(x) unlink(x) #endif typedef unsigned char BYTE; typedef char SBYTE; typedef unsigned long ULONG; typedef int BOOL; #define TRUE 1 #define FALSE 0 typedef struct { ULONG fromSeg; ULONG toSeg; BOOL isEnd; ULONG tempFileName; ULONG validLength; char *filename; } FRAGREC; int main( int argc, char *argv[] ); void DecodeFile( FILE *fin ); ULONG FindHeader( FILE *fin, char *filename ); int GetNthToken( char *destStr, char line[], int tokenNumber ); void BuildDecodeTable( void ); BOOL DecodeSeg( FILE *fin, FILE *fout, ULONG segnum, char *filename, BOOL *isEnd, ULONG *outSeglen ); int DecodeBcodeLine( char line[], int lineLen, BYTE buf[], ULONG *totalCrc ); int DecodeUucodeLine( char line[], int lineLen, BYTE buf[], ULONG *totalCrc ); int DecodeHexcodeLine( char line[], int lineLen, BYTE buf[], ULONG *totalCrc ); void CrcTableGen( void ); void LoadStatusFile( void ); void SaveStatusFile( void ); void WriteStatusData( FILE *fout ); FILE *GetTempFile( char *filename, ULONG segnum, ULONG *fragRec ); ULONG GetFreeTempName( void ); void GetTempNameStr( ULONG tempName, char *s ); void ErrorPreramble( char *s ); ULONG InsertFragRec( ULONG segnum, ULONG tempName, char *filename ); void CheckCoalesce( ULONG fragRec ); void CheckComplete( ULONG fragRec ); void RemoveFragRec( ULONG rec ); void DiscardSegment( ULONG fragRec ); int ReadLine( FILE *fin, char *buf ); #ifdef NO_RENAME int rename( char *oldname, char *newname ); #endif char *progname; BOOL informative; BOOL verbose; BOOL debug; BOOL force; /* force decoding - ignore errors */ BOOL spitNames; /* spit decoded file names out stdout */ char *readFilename; ULONG readLineNum; FRAGREC frags[MAX_FRAG]; ULONG fragCount; int format; BOOL statusFileExists; ULONG nextTempName; ULONG hexcodeFilepos; char pushedHeader[MAX_LINE]; char *tempPrefix; BOOL prefixUsed; BYTE copyBuf[COPY_BUF_SIZE]; SBYTE decodeTable[ 256 ]; ULONG crcTable[ 256 ]; char base64Char[64] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' }; char uucodeChar[64] = { '`','!','"','#','$','%','&','\'','(',')','*','+',',', '-','.','/', '0','1','2','3','4','5','6','7', '8','9',':',';','<', '=','>','?', '@','A','B','C','D','E','F','G', 'H','I','J','K','L', 'M','N','O', 'P','Q','R','S','T','U','V','W', 'X','Y','Z','[','\\',']','^','_' }; /****************************************************************************/ int main( int argc, char *argv[] ) { FILE *fin; int i, j, dasharg; BOOL filenameUsed; progname = argv[0]; filenameUsed = FALSE; informative = FALSE; verbose = FALSE; debug = FALSE; force = FALSE; spitNames = FALSE; prefixUsed = FALSE; tempPrefix = ""; strcpy( pushedHeader, "Yo" ); CrcTableGen(); LoadStatusFile(); i = 1; while (i=argc) { fprintf(stderr, "%s: no argument for -p flag\n", progname); exit( 1 ); } tempPrefix = argv[i]; prefixUsed = TRUE; break; default: fprintf(stderr, "unbcode version %s\n\n", VERSION); fprintf(stderr, "usage: %s [-ivdnf] [-p pr",progname); fprintf(stderr, "efix] [filename ...]\n\n"); fprintf(stderr, "-i : \"informative\" mode: tells yo"); fprintf(stderr, "u when files are recombined\n"); fprintf(stderr, "-v : verbose mode: tells you what it"); fprintf(stderr, " is up to\n"); fprintf(stderr, "-d : debugging mode: tells you about"); fprintf(stderr, " the file fragments it is juggling\n"); fprintf(stderr, "-n : spits out names (only) of files"); fprintf(stderr, " extracted and recombined\n"); fprintf(stderr, "-f : force: ignores decoding errors\n"); fprintf(stderr, "-p : give filename prefix for temporary"); fprintf(stderr, " files\n"); fprintf(stderr, "-help : gives usage information\n"); exit( 1 ); break; } } } else { filenameUsed = TRUE; if (verbose) { fprintf(stderr, "%s: decoding file \"%s\"\n",progname,argv[i]); } if( (fin = fopen(argv[i], "r")) == NULL) { fprintf(stderr, "%s: error opening \"%s\"\n",progname,argv[i]); } else { readFilename = argv[i]; readLineNum = 0; DecodeFile( fin ); fclose( fin ); } } i++; } if (!filenameUsed) { if (verbose) { fprintf(stderr, "%s: decoding from standard input\n", progname); } readFilename = ""; readLineNum = 0; DecodeFile( stdin ); } SaveStatusFile(); return( 0 ); } /****************************************************************************/ void DecodeFile( FILE *fin ) { char filename[MAX_FILENAME]; ULONG segnum, seglen; FILE *fout; BOOL err, isEnd; ULONG fragRec; while (TRUE) { segnum = FindHeader( fin, filename ); if (segnum == 0) return; if (verbose) { fprintf(stderr, "%s: decoding segment %lu of file %s\n", progname, segnum, filename); } BuildDecodeTable(); fout = GetTempFile( filename, segnum, &fragRec ); if (fout == NULL) continue; err = DecodeSeg( fin, fout, segnum, filename, &isEnd, &seglen ); fclose( fout ); if (err) { fprintf(stderr, "%s: error decoding segment ", progname); fprintf(stderr, "#%lu of file \"%s\", discarding it\n", segnum, filename); DiscardSegment( fragRec ); } else { frags[fragRec].isEnd = isEnd; frags[fragRec].validLength += seglen; CheckCoalesce( fragRec ); CheckComplete( fragRec ); } if (debug) { fprintf(stderr, "---File-Fragments---\n"); WriteStatusData( stderr ); fprintf(stderr, "--End-of-Fragments--\n"); } } } /****************************************************************************/ ULONG FindHeader( FILE *fin, char *filename ) { char line[MAX_LINE]; int len, scan, pos; ULONG segnum; char c1, c2, c3, dummyc; strcpy( line, pushedHeader ); len = strlen( line ); strcpy( pushedHeader, "nothing" ); while( TRUE ) { if (len == -1) return( 0 ); if (line[0]=='-') { for (pos=0; pos<=1; pos++) { scan = sscanf(&line[pos], "-bcode-begin %lu %c", &segnum, &dummyc); if (scan == 2 && segnum >= 1) { GetNthToken( filename, line, 3 ); format = BCODE; return( segnum ); } scan = sscanf(&line[pos], "-nucode-begin %lu %c", &segnum, &dummyc); if (scan == 2 && segnum >= 1) { GetNthToken( filename, line, 3 ); format = UUCODE; return( segnum ); } scan = sscanf(&line[pos], "-hexcode-begin %lu %c", &segnum, &dummyc); if (scan == 2 && segnum >= 1) { GetNthToken( filename, line, 3 ); format = HEXCODE; return( segnum ); } } } else if (line[0]=='b' && line[1]=='e') { scan = sscanf(line, "begin %c%c%c %c", &c1, &c2, &c3, &dummyc); if (scan == 4 && segnum >= 1 && (c1>='0'&&c1<='7') && (c2>='0'&&c2<='7') && (c3>='0'&&c3<='7') ) { GetNthToken( filename, line, 3 ); format = UUCODE; segnum = 1; return( segnum ); } } len = ReadLine( fin, line ); } } /****************************************************************************/ int GetNthToken( char *destStr, char line[], int tokenNumber ) { int i, tok; i = 0; tok = 1; while (line[i]!='\0') { /* skip whitespace before token */ while (line[i]==' ' || line[i]=='\t' || line[i]=='\n') i++; /* check if we are done */ if (tok >= tokenNumber) { strcpy( destStr, &line[i] ); return( i ); } tok++; /* skip intermediate token characters */ while (line[i]!='\0' && line[i]!=' ' &&line[i]!='\t' &&line[i]!='\n'){ i++; } } return( -1 ); } /****************************************************************************/ void BuildDecodeTable( void ) { int i, v; for (i=0; i<=255; i++) decodeTable[i] = -1; v = 0; switch( format ) { case BCODE: for (i=0; i<64; i++) { decodeTable[ base64Char[i] ] = v++; } decodeTable['='] = 0; break; case UUCODE: for (i=0; i<64; i++) { decodeTable[ uucodeChar[i] ] = v++; } decodeTable[' '] = 0; break; case HEXCODE: for (i='0'; i<='9'; i++) { decodeTable[ i ] = v++; } for (i='a'; i<='f'; i++) { decodeTable[ i ] = v++; } break; } } /****************************************************************************/ BOOL DecodeSeg( FILE *fin, FILE *fout, ULONG segnum, char *filename, BOOL *isEnd, ULONG *outSeglen ) { ULONG seglen, segcrc; ULONG statNum, statLen, statCrc; int len, scan, off, pos; BYTE buf[MAX_CHUNK+3]; char line[MAX_LINE]; char chkstr[MAX_FILENAME]; char c1, c2, c3; seglen = 0; segcrc = 0xFFFFFFFF; *isEnd = TRUE; *outSeglen = 0; hexcodeFilepos = 0; while( TRUE ) { len = ReadLine( fin, (char*)line ); if (len == -1) { ErrorPreramble("unexpected EOF encountered\n"); return( TRUE ); } if (format==BCODE && line[0]=='-') break; if (format==UUCODE && (line[0]=='`' || line[0]==' ' || (line[0]=='-' && line[1]=='-' && line[2]=='n') || (line[0]=='-' && line[1]=='n')) ) break; if (format==HEXCODE && line[0]=='-') break; switch( format ) { case BCODE: len = DecodeBcodeLine( line, len, buf, &segcrc ); break; case HEXCODE: len = DecodeHexcodeLine( line, len, buf, &segcrc ); break; case UUCODE: if (line[0]=='b') { scan = sscanf(line, "begin %c%c%c %s", &c1, &c2, &c3, chkstr); if (scan == 4 && (c1>='0'&&c1<='7') && (c2>='0'&&c2<='7') && (c3>='0'&&c3<='7') ) { /* ignore duplicate begin line */ GetNthToken( chkstr, line, 3 ); if (strcmp(filename, chkstr)!=0 ) { ErrorPreramble( /*indent next line*/ "Ignoring inconsistent filename on uucode \"begin\" line\n" ); } len = 0; } else { len = DecodeUucodeLine( line, len, buf, &segcrc ); } } else { len = DecodeUucodeLine( line, len, buf, &segcrc ); } break; } if (len == -1) { if (force) { /* ignore the error line */ len = 0; fprintf(stderr, "%s: force mode in effect: ignoring error line\n", progname); } else { /* report invalid segment */ return( TRUE ); } } fwrite( buf, sizeof(BYTE), len, fout ); seglen += len; } segcrc ^= 0xFFFFFFFF; *outSeglen = seglen; switch( format ) { case BCODE: off = 0; for (pos=0; pos<=1; pos++) { if( strncmp("-bcode-end ", &line[pos], 11)==0 ) { off = 11 + pos; *isEnd = TRUE; break; } else if( strncmp("-bcode-continued ", &line[pos], 17)==0 ) { off = 17 + pos; *isEnd = FALSE; break; } } if (off==0) { ErrorPreramble("Invalid BCODE control token\n"); return( !force ); } break; case HEXCODE: off = 0; for (pos=0; pos<=1; pos++) { if( strncmp("-hexcode-end ", &line[pos], 13)==0 ) { off = 13 + pos; *isEnd = TRUE; break; } else if( strncmp("-hexcode-continued ", &line[pos], 19)==0 ) { off = 19 + pos; *isEnd = FALSE; break; } } if (off==0) { ErrorPreramble("Invalid HEXCODE control token\n"); return( !force ); } break; case UUCODE: if( line[0]=='`' || line[0]==' ' ) { off = -1; /* scan ahead for the "end" and maybe "--nucode-" or "-nucode"*/ len = ReadLine( fin, line ); if ( len>1 && strcmp(line, "end")==0 ) { /* we have scanned the "end" line, try for the "nucode" line */ len = ReadLine( fin, line ); if (strncmp("-nucode-end ", line, 12)==0 || strncmp("--nucode-end ", line, 13)==0 || strncmp("-nucode-continued ", line, 18)==0 || strncmp("--nucode-continued ", line, 19)==0 ) { /* got the "nucode" ending line; use it below */ off = 0; } strcpy( pushedHeader, line ); } else { /* couldn't get the "end" line; push what we got, return err */ strcpy( pushedHeader, line ); ErrorPreramble( "Uucode end marker not followed by \"end\" line\n"); return( !force ); } } else { off = 0; } if (off==0) { for (pos=0; pos<=1; pos++) { if( strncmp("-nucode-end ", &line[pos], 12)==0 ) { off = 12 + pos; *isEnd = TRUE; break; } else if( strncmp("-nucode-continued ", &line[pos], 18)==0 ) { off = 18 + pos; *isEnd = FALSE; break; } } if (off==0) { ErrorPreramble("Invalid NUCODE control token\n"); return( !force ); } } break; } if (off > 0) { scan = sscanf(&line[off], "%lu %lu %08lx", &statNum, &statLen, &statCrc); if (scan != 3) { scan = sscanf(&line[off], "%lu %lu %s", &statNum, &statLen,chkstr); if (scan==3 && strcmp(chkstr,"nocrcxxx")==0) { statCrc = segcrc; } else { scan = 0; } } } else { scan = 3; statNum = segnum; statLen = seglen; statCrc = segcrc; } if (scan != 3) { ErrorPreramble("Invalid control line format\n"); return( !force ); } if (statNum != segnum) { ErrorPreramble("Mismatching segment numbers\n"); return( !force ); } if (statLen != seglen && statLen != 0) { ErrorPreramble("Mismatching segment lengths\n"); return( !force ); } if (statCrc != segcrc) { ErrorPreramble("Mismatching CRC-32 values\n"); return( !force ); } return( FALSE ); } /****************************************************************************/ int DecodeBcodeLine( char line[], int lineLen, BYTE buf[], ULONG *totalCrc ) { register int c0,c1,c2,c3; register ULONG crc; register int bufpos, linepos, len; crc = *totalCrc; if (lineLen%4 != 0) { ErrorPreramble("Invalid BCODE line length\n"); return( -1 ); } if (lineLen == 0) return( 0 ); for (bufpos = 0, linepos = 0; linepos < lineLen; bufpos+=3, linepos+=4) { c0 = decodeTable[ line[linepos ] ]; c1 = decodeTable[ line[linepos+1] ]; c2 = decodeTable[ line[linepos+2] ]; c3 = decodeTable[ line[linepos+3] ]; if (c0==-1 || c1==-1 || c2==-1 || c3==-1) { ErrorPreramble("Invalid character in BCODE data\n"); return( -1 ); } buf[bufpos ] = (c0<<2) | ((c1&0x30)>>4); buf[bufpos+1] = ((c1&0x0F)<<4) | ((c2&0x3C)>>2); buf[bufpos+2] = ((c2&0x03)<<6) | c3; } /* fix non-integral-length (last) line */ if (line[lineLen-1] == '=') bufpos--; if (line[lineLen-2] == '=') bufpos--; len = bufpos; /* take crc of binary data */ for( bufpos=0; bufpos < len; bufpos++ ) { crc = ((crc>>8) & 0x00FFFFFF) ^ crcTable[ (crc^buf[bufpos]) & 0xFF]; } *totalCrc = crc; return( len ); } /****************************************************************************/ int DecodeUucodeLine( char line[], int lineLen, BYTE buf[], ULONG *totalCrc ) { register int c0,c1,c2,c3; register ULONG crc; register int bufpos, linepos, len; crc = *totalCrc; if (lineLen == 0) { ErrorPreramble("Blank line found in uucode data\n"); return( -1 ); } len = decodeTable[ line[0] ]; if (len<0) { ErrorPreramble("Invalid character for uucode line length\n"); return( -1 ); } if ( 1+((len+2)/3)*4 > lineLen ) { ErrorPreramble("Uucode line length longer than actual line\n"); return( -1 ); } for (bufpos = 0, linepos = 1; bufpos>4); buf[bufpos+1] = ((c1&0x0F)<<4) | ((c2&0x3C)>>2); buf[bufpos+2] = ((c2&0x03)<<6) | c3; } /* take crc of binary data */ for( bufpos=0; bufpos < len; bufpos++ ) { crc = ((crc>>8) & 0x00FFFFFF) ^ crcTable[ (crc^buf[bufpos]) & 0xFF]; } *totalCrc = crc; return( len ); } /****************************************************************************/ int DecodeHexcodeLine( char line[], int lineLen, BYTE buf[], ULONG *totalCrc ) { register int c0, c1, b0; register ULONG crc, cksum; register int bufpos, linepos, len; ULONG lineAddr, lineCksum; int lineDataStart, lineDataEnd, i; crc = *totalCrc; /* handle line address */ lineAddr = 0; for (i=0; i=lineLen || line[i]!=':') { ErrorPreramble("Invalid HEXCODE line address format\n"); return( -1 ); } if (hexcodeFilepos==0) { hexcodeFilepos = lineAddr; } if (lineAddr != hexcodeFilepos) { ErrorPreramble("Invalid HEXCODE line address\n"); hexcodeFilepos = lineAddr; return( -1 ); } lineDataStart = i+1; /* fetch line checksum */ if (lineLen>=3) { c0 = decodeTable[ line[ lineLen-2 ] ]; c1 = decodeTable[ line[ lineLen-1 ] ]; } if (lineLen<3 || c0==-1 || c1==-1 || line[lineLen-3]!=':') { ErrorPreramble("Invalid HEXCODE line checksum format\n"); return( -1 ); } lineCksum = c0 * 16 + c1; lineDataEnd = lineLen-3; /* decode line */ bufpos = 0; cksum = 0; for (linepos=lineDataStart; linepos>8) & 0x00FFFFFF) ^ crcTable[ (crc^buf[bufpos]) & 0xFF]; } *totalCrc = crc; return( len ); } /****************************************************************************/ void CrcTableGen( void ) { unsigned long crc, poly; int i, j; poly = 0xEDB88320L; for (i=0; i<256; i++) { crc = i; for (j=8; j>0; j--) { if (crc&1) { crc = (crc >> 1) ^ poly; } else { crc >>= 1; } } crcTable[i] = crc; } } /****************************************************************************/ void LoadStatusFile( void ) { char line[MAX_LINE]; char filename[MAX_FILENAME]; FILE *fin; int scan; FRAGREC*h; char interpret[4], dummyc; fragCount = 0; statusFileExists = FALSE; nextTempName = 1; sprintf(filename, "%s0BC-STAT", tempPrefix); if( (fin = fopen(filename, "r")) == NULL) return; statusFileExists = TRUE; while ( ReadLine( fin, line ) != -1 ) { h = & frags[fragCount]; scan = sscanf(line, "%05lu-%05lu %c%c%c %010lu 0BC%05lx %c", &h->fromSeg, &h->toSeg, &interpret[0], &interpret[1], &interpret[2], &h->validLength, &h->tempFileName, &dummyc); if (scan != 8) { fprintf(stderr, "Bad Status Line: %s\n", line); } else { GetNthToken( filename, line, 5 ); h->isEnd = (interpret[0] == 'e'); h->filename = (char*)malloc( strlen(filename)+1 ); strcpy( h->filename, filename ); fragCount++; if (fragCount>=MAX_FRAG) { fprintf(stderr, "too many status fragments, FATAL\n"); exit( 1 ); } } } fclose( fin ); } /****************************************************************************/ void SaveStatusFile( void ) { char filename[MAX_FILENAME]; FILE *fout; int err; sprintf(filename, "%s0BC-STAT", tempPrefix); if (fragCount == 0) { if (statusFileExists) { err = remove( filename ); if (err) { fprintf(stderr,"cannot remove %s\n", filename); } } return; } if( (fout = fopen(filename, "w")) == NULL) { fprintf(stderr, "cannot open %s for saving status\n",filename); return; } WriteStatusData( fout ); fclose( fout ); } /****************************************************************************/ void WriteStatusData( FILE *fout ) { ULONG i; FRAGREC *h; char interpret[4]; for (i=0; iisEnd) { strcpy( interpret, "end" ); } else { if (h->fromSeg == 1) { strcpy( interpret, "beg" ); } else { strcpy( interpret, "mid" ); } } fprintf(fout, "%05lu-%05lu %s %010lu 0BC%05lu %s\n", h->fromSeg, h->toSeg, interpret, h->validLength, h->tempFileName, h->filename); } } /****************************************************************************/ FILE *GetTempFile( char *filename, ULONG segnum, ULONG *fragRec ) { FRAGREC*h; ULONG i, rec, tempName; char tempname[MAX_FILENAME]; char tempmode[4]; BOOL append; FILE *fout; /* search to append to existing file */ append = FALSE; for (i=0; ifilename)==0) { if (h->fromSeg<=segnum && segnum<=h->toSeg) { ErrorPreramble("Ignoring duplicate segment"); fprintf(stderr, " %lu of \"%s\"\n", segnum, filename); return( NULL ); } if (segnum == h->toSeg + 1) { /* append */ tempName = h->tempFileName; strcpy( tempmode, "ab" ); append = TRUE; h->toSeg = segnum; h->isEnd = FALSE; rec = i; break; } } } if (!append) { /* find new tempname */ tempName = GetFreeTempName(); /* create new frag record */ rec = InsertFragRec( segnum, tempName, filename ); strcpy(tempmode, "wb"); } /* open the temporary file */ GetTempNameStr( tempName, tempname ); if( (fout = fopen(tempname, tempmode)) == NULL) { fprintf(stderr, "%s: error opening \"%s\" for write, FATAL!\n", progname, filename); exit( 1 ); } *fragRec = rec; return( fout ); } /****************************************************************************/ ULONG GetFreeTempName( void ) { long i, j; ULONG tempName; for (i=0; i<100000; i++) { tempName = nextTempName; nextTempName = (nextTempName + 1) % 100000; for (j=0; j= MAX_FRAG) { fragCount--; fprintf(stderr, "input data too fragmented; FATAL!\n"); exit( 1 ); } /* insertion sort new entry into place */ for (i=rec-1; i>=0; i--) { cmp = strcmp(filename, frags[i].filename); if (cmp > 0) { break; } else if (cmp==0 && segnum>frags[i].fromSeg) { break; } frags[i+1] = frags[i]; } /* initialize new record */ rec = i+1; h = & frags[rec]; h->fromSeg = segnum; h->toSeg = segnum; h->isEnd = FALSE; h->tempFileName = tempName; h->validLength = 0; h->filename = (char*)malloc( strlen(filename)+1 ); strcpy( h->filename, filename ); return( rec ); } /****************************************************************************/ void CheckCoalesce( ULONG fragRec ) { FRAGREC *p, *q; char tempname[MAX_FILENAME]; int err; FILE *fin, *fout; int bytes; if (fragRec >= fragCount-1) return; p = & frags[fragRec]; q = & frags[fragRec+1]; if (strcmp(p->filename, q->filename)!=0 || p->toSeg+1 != q->fromSeg) { return; } /* coalesce */ if (debug) { fprintf(stderr,"Coalescing segs %lu-%lu and segs %lu-%lu of file %s\n", p->fromSeg, p->toSeg, q->fromSeg, q->toSeg, p->filename); } /* copy file contents */ GetTempNameStr( q->tempFileName, tempname ); if( (fin = fopen(tempname, "rb")) == NULL) { fprintf(stderr, "%s: error opening \"%s\", FATAL\n",progname,tempname); exit( 1 ); } GetTempNameStr( p->tempFileName, tempname ); if( (fout = fopen(tempname, "ab")) == NULL) { fprintf(stderr, "%s: error opening \"%s\", FATAL\n",progname,tempname); exit( 1 ); } while ( (bytes=fread( copyBuf, sizeof(BYTE), COPY_BUF_SIZE, fin)) >0) { fwrite( copyBuf, sizeof(BYTE), bytes, fout ); } fclose( fout ); fclose( fin ); /* remove old record and temp file */ p->toSeg = q->toSeg; p->isEnd = q->isEnd; p->validLength += q->validLength; GetTempNameStr( q->tempFileName, tempname ); err = remove( tempname ); if (err) { fprintf(stderr, "cannot remove %s, continuing.\n", tempname); } RemoveFragRec( fragRec+1 ); } /****************************************************************************/ void CheckComplete( ULONG fragRec ) { char tempname[MAX_FILENAME]; int err, bytes; FRAGREC*h; FILE *fin, *fout; h = & frags[fragRec]; if (!h->isEnd || h->fromSeg!=1) return; GetTempNameStr( h->tempFileName, tempname ); if (prefixUsed) { /* must copy file contents--may cross directory/device */ if( (fin = fopen(tempname, "rb")) == NULL) { fprintf(stderr, "%s: error opening \"%s\", FATAL\n", progname, tempname); exit( 1 ); } if( (fout = fopen(h->filename, "wb")) == NULL) { fprintf(stderr, "%s: error opening \"%s\", continuing\n", progname, h->filename); fclose( fin ); } if (fout != NULL) { while ( (bytes=fread(copyBuf,sizeof(BYTE),COPY_BUF_SIZE,fin)) >0) { fwrite( copyBuf, sizeof(BYTE), bytes, fout ); } fclose( fout ); fclose( fin ); err = remove( tempname ); if (err) { fprintf(stderr, "%s: cannot remove \"%s\", continuing\n", progname, tempname); } } } else { /* rename temp file to final filename--in same directory */ err = rename( tempname, h->filename ); if (err) { fprintf(stderr, "cannot rename %s to %s, continuing.\n", tempname, h->filename ); } } if (informative) { fprintf(stderr, "%s: extracted \"%s\"\n", progname, h->filename ); } if (spitNames) { printf("%s\n", h->filename); } RemoveFragRec( fragRec ); } /****************************************************************************/ void RemoveFragRec( ULONG rec ) { long i; /* free dynamic memory of filename */ free( frags[rec].filename ); /* pull all higher entries back one position */ for (i=rec; ifromSeg == f->toSeg) { /* discard entire fragment--easy */ GetTempNameStr( f->tempFileName, filename ); err = remove( filename ); if (err) { fprintf(stderr, "%s: cannot remove \"%s\", continuing\n", progname, filename); } RemoveFragRec( fragRec ); } else { /* discard last segment of a fragment--hard */ newtemp = GetFreeTempName(); /* copy valid contents into new temporary file */ GetTempNameStr( f->tempFileName, filename ); if( (fin = fopen(filename, "rb")) == NULL) { fprintf(stderr, "%s: error opening \"%s\", FATAL!\n", progname, filename); exit( 1 ); } GetTempNameStr( newtemp, filename ); if( (fout = fopen(filename, "wb")) == NULL) { fprintf(stderr, "%s: error opening \"%s\", FATAL!\n", progname, filename); exit( 1 ); } remlen = f->validLength; while( TRUE ) { if (remlen <= 0) break; buflen = (remlentempFileName, filename ); if (remlen>0) { fprintf(stderr, "%s: unexpectedly short file \"%s\", FATAL!\n", progname, filename); exit( 1 ); } fclose( fout ); fclose( fin ); /* remove old temporary file */ err = remove( filename ); if (err) { fprintf(stderr, "%s: cannot remove \"%s\", continuing\n", progname, filename); } /* update fragment record */ (f->toSeg)--; f->tempFileName = newtemp; } } /****************************************************************************/ int ReadLine( FILE *fin, char *buf ) { char *r; char junkline[MAX_LINE]; int len; r = fgets( buf, MAX_LINE, fin ); if (r==NULL) return( -1 ); len = strlen(buf)-1; if (buf[len] == '\n') { buf[len] = '\0'; } else { len++; do { r = fgets( junkline, MAX_LINE, fin ); } while (r!=NULL && junkline[strlen(junkline)-1]!='\n'); } readLineNum++; return( len ); } /****************************************************************************/ #ifdef NO_RENAME int rename( char *oldname, char *newname ) { if ( link( oldname, newname )) return( -1 ); else return( unlink( oldname )); } #endif /******************************************************************--END--***/