⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 expand.c

📁 DOS 源代码 系列之 command 源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*          Data Decompression Program
            written by Steve Zeck and David Dickman

            Copyright (c) 1989-1991 by Microsoft Corporation
            Microsoft Confidential
            All Rights Reserved.

   This program will decompress files using the Lempel-Zev compress algorithm.
   A header is prepended to the file being compressed which contains a
   signature block and other information, like the size of the uncompressed
   file.  Other compression algorithms may be added fairly easily.  The
   compressed file header contains tags for the algorithm used in compression
   and the version of the program which compressed the file.  The last file
   modification date is preserved through compression and decompression.

   Fragmented Compression:
   ----------------------

   Compression of files which, even when compressed, occupy more than one
   floppy disk is handled in a primitive way.  Once compress runs out of disk
   space during a write, it asks for a new disk, and continues compression
   into a file of the same output name on the new disk.  Decompressing a
   fragmented output file takes more work.  The compressed output files must
   be appended together in their output order before decompressing the
   resulting unfragmented compressed file.  Of course, this requires a hard
   disk or some medium with sufficient space to hold the unfragmented
   compressed file.

   For example, suppose a large program called "bogusxl.exe" still occupies
   900Kb even when compressed.  It is to be shipped on 360Kb floppy disks.
   Working from a directory containing the original version of bogusxl.exe on
   drive c, bogusxl.exe might be compressed into bogusxl.out with the
   following command line:

   C:>compress e bogusxl.exe bogusxl.out

   compress will try to fit as much of the compressed data on each diskette
   as possible.  Assuming compress is handed empty 360Kb formatted floppy
   disks, bogusxl.out will be split into three fragments: 360Kb on disk 1,
   360Kb on disk 2, and 180Kb on disk 3 (in order).  The compressed data file
   on each disk is named bogusxl.out.  You might want to rename the files on
   the floppy disks.  e.g., bogusxl.1 on disk 1, bogusxl.2 on disk 2, and
   bogusxl.3 on disk 3.  Now we need to create an unfragmented version (e.g.,
   on hard drive c: on the purchaser's pc).

   <working from the target directory on c:>
   <insert disk 1 in drive a:>
   C:>copy a:bogusxl.1 c:

   <insert disk 2 in drive a:>
   C:>copy a:bogusxl.2 c:

   <insert disk 3 in drive a:>
   C:>copy a:bogusxl.3 c:

   Now to stitch together the three fragments in order.

   C:>copy bogusxl.1 /b + bogusxl.2 /b + bogusxl.3 /b bogusxl.out

   However, the date and time stamp of bogusxl.out no longer matches that of
   the original version of bogusxl.exe.  To fix this, use the 's' (set time
   and date) option of compress to copy bogusxl.1's stamp to bogusxl.out:

   C:>compress s bogusxl.1 bogusxl.out

   Now bogusxl.out is an unfragmented compressed version of bogusxl.exe, so
   it just needs to be decompressed.

   C:>compress d bogusxl.out bogusxl.exe

   And we can get rid of the compressed files...

   C:>del bogusxl.1
   C:>del bogusxl.2
   C:>del bogusxl.3
   C:>del bogusxl.out

   So now an uncompressed copy of bogusxl.exe with matching date and time
   stamp is on the user's hard drive.

   (A future version of compress may try to mitigate this multi-file
   rigamarole.)

****************************************************************************/
/*
   Notes:
   -----

   Fragmented compression needs to be tidied up.  e.g., a fragment number
   (UCHAR) could be added to the compressed file header to help automate
   fragmented decompression.  The 's' command line option is an especially
   klugey example of the messy fragmented compression handling.
*/

/* History:
 *
 * 08/07/91	M001	Added the following functionality:
 *						1) Do not allow source file to overwrite itself.
 *						2) If source file cannot be found, try file name with 3rd
 *							character of extension set = '_'.
 *						3) Display status messages as each file is expanded (like
 *							COPY, but display status even if just expanding 1 file):
 *								A:\EGA.SY_ -> C:\DOS\EGA.SYS
 *							Each message will appear on a new line, so if multiple
 *							files are expanded, the screen will scroll.
 *						4) Number of input parameters:
 *							a) = 0: Prompt for source file and destination file/path
 *							b) = 1: Prompt for destination file/path
 *							c) = 2:	Source must be file name
 *										Destination can be file name or existing
 *										 directory name (path)
 *							d) > 2:	First parameters (sources) must be file names
 *										Last parameter (destination) must be existing
 *										directory name (path)
 *						5) Destination file name:
 *							a) Can be explicitly specified when only 1 file is
 *								being expanded.
 *							b) When no destination file name is specified, the
 *								source file name is used as specified on command-line
 *								(i.e. if "EXPAND A:\EGA.SYS  C:\DOS" finds A:\EGA.SY_,
 *								it will display the status message
 *								"A:\EGA.SY_ -> C:\DOS\EGA.SYS"
 *								and create the file C:\DOS\EGA.SYS).
 *
 * 11/09/89	CC		Copied from compress.c and isolated
 *						expand features.	Retained former features since we
 *						may want them later (see #ifdef OLD's).
 */



// Headers
///////////
#include <stdio.h>
#include <stdlib.h>				/* M001 */
#include <string.h>
#include <ctype.h>
#include <conio.h>
#include <io.h>
#include <dos.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <malloc.h>

#include "expand.h"
#include "expmsgs.h"

#include <decomp.h>

// M001: Local Prototypes
//////////////////////////

static unsigned fnFileCopy(int fhDst,int fhSrc);
static BOOL PromptUser(int, char **);
static int Quit(int);
static int ProcessInput(int, char **);
static int GetString(char *, int);
static int GetSourceHandle(char *);
static BOOL IsSourceDest(char *, char *);

// Globals
///////////
static long cblInSize,                 // size in bytes of original file
            cblOutSize = 0L;           // size in bytes of output file

static int iCurMatch,                  // index and length of longest match
           cbCurMatch;                 // (set by LZInsertNode())

static int leftChild[cbRingBufMax + 1],    // left, right children and parents
           rightChild[cbRingBufMax + 257], // (these arrays make up the binary
           parent[cbRingBufMax + 1];       // search trees)

static char *pszInFile,                  // names of input and output files
            *pszOutFile;

static UCHAR uchAlgorithm,                // algorithm label
             uchVersion;                  // version id

static int doshIn,                     // input and output DOS file handles
           doshOut;

static int wOriginalDrive;

static int iFiles;					/* M001: # of files successfully expanded */


// DOS file handles are used for file references in this module since using
// FILE *'s for file references poses a problem.  fclose()'ing a file which
// was fopen()'ed in write "w" or append "a" mode stamps the file with the
// current date.  This undoes the effect of copyCreateDate().  Could also get
// around this fclose() problem by first fclose()'ing the file, and
// fopen()'ing it again in read "r" mode.
//
// Using file handles also allows us to bypass stream buffering, so read's
// and write's may be done with whatever buffer size is desired.  Also, the
// lower-level DOS file handle functions are faster than their stream
// counterparts.


#ifdef DBCS
/*
	Test if the character is DBCS lead byte

	input:	c = character to test
	output:	TRUE if leadbyte
*/

int	IsDBCSLeadByte(c)
unsigned char c;
{
	static unsigned char far *DBCSLeadByteTable = NULL;

	union REGS inregs,outregs;
	struct SREGS segregs;
	unsigned char far *p;

	if (DBCSLeadByteTable == NULL)
	{
		inregs.x.ax = 0x6300;		/* get DBCS lead byte table */
		intdosx(&inregs, &outregs, &segregs);
		FP_OFF(DBCSLeadByteTable) = outregs.x.si;
		FP_SEG(DBCSLeadByteTable) = segregs.ds;
	}

	p = DBCSLeadByteTable;
	while (p[0] || p[1])
	{
		if (c >= p[0] && c <= p[1])
			return TRUE;
		p += 2;
	}
	return FALSE;
}

/*
	Check if the character point is at tail byte

	input:	*str = strart pointer of the string
		*point = character pointer to check
	output:	TRUE if at the tail byte
*/

int	CheckDBCSTailByte(str,point)
unsigned char *str,*point;
{
	unsigned char *p;

	p = point;
	while (p != str)
	{
		p--;
		if (!IsDBCSLeadByte(*p))
		{
			p++;
			break;
		}
	}
	return ((point - p) & 1 ? TRUE : FALSE);
}
#endif


BOOL HelpSwitchPresent(int argc, char *argv[])
{
   int i;

	for (i = 1; i < argc; i++)
      if (strcmp(argv[i], pszHELP_SWITCH) == 0)
         return(TRUE);

   return(FALSE);
} // HelpSwitchPresent()



void CatPathAndFileName(char *pszPath, char *pszFileName)
{
   if (*pszFileName != '\0')
   {
#ifdef DBCS
      if ((! SLASH(pszPath[strlen(pszPath) - 1]) &&
          (pszPath[strlen(pszPath) - 1]) != ':') ||
          CheckDBCSTailByte(pszPath,&pszPath[strlen(pszPath) - 1]))
#else
      if (! SLASH(pszPath[strlen(pszPath) - 1]) &&
          (pszPath[strlen(pszPath) - 1]) != ':')
#endif
         strcat(pszPath, CHSEPSTR);

      strcat(pszPath, pszFileName);
   }
} // CatPathAndFileName()



char *ExtractFileName(char *pszPath)
{
   char *psz;

   for (psz = pszPath; *psz != '\0'; psz++)
      ;

#ifdef DBCS
   for ( ; psz >= pszPath && ((! SLASH(*psz) && *psz != ':') ||
   		CheckDBCSTailByte(pszPath,psz)) ; psz--)
#else
   for ( ; psz >= pszPath && ! SLASH(*psz) && *psz != ':'; psz--)
#endif
      ;

   return(++psz);
} // ExtractFileName()


char ExtractDrive(char *pszFileName)
{
   return(pszFileName[1] == ':' ?
          pszFileName[0] :
          (char)('a' + wOriginalDrive));
}



// WriteOutBuf()
//
// Dumps output buffer to output (compressed) file.  Prompts for new floppy
// disk if old one if full.  Continues dumping to output file of same name on
// new floppy disk.  The only error codes it may return are
// LZERROR_BADINHANDLE and LZERROR_BADOUTHANDLE (from copyCreateDate()).
//
int WriteOutBuf(UCHAR uch,    // first character to be added to the empty
                              // buffer after the full buffer is written
                int doshDest) // output file handle
{
   unsigned ucbToWrite,       // number of bytes to write from buffer
            ucbWritten,       // number of bytes actually written
            ucbTotWritten;    // total number of bytes written to output
   char chDrive;
   int f;                     // holds copyCreateDate() return value

   // how much of the buffer should be written to the output file?
   ucbTotWritten = ucbToWrite = (unsigned)(puchOutBuf - rguchOutBuf);
   // reset pointer to beginning of buffer
   puchOutBuf = rguchOutBuf;

   // do not write to an output file if given the 'q' command line option
   if (doshDest == NO_DOSH)
   {
      cblOutSize += (long)ucbTotWritten;
      return((int)uch);
   }

   while ((ucbWritten = FWRITE(doshDest, puchOutBuf, ucbToWrite)) != ucbToWrite)
   {
      // ran out of disk space
      if (DosRemoveable(chDrive = ExtractDrive(pszOutFile)))
         do
         {
            // shut down the old output file
            if ((f = CopyCreateDate(doshIn, doshDest)) != COPYCREATEDATE_OK)
               return(f);
            FCLOSE(doshDest);
            printf(pszINSERT_NEW_DISK, chDrive);
            getchar();
         // open a new output file of the same name
         } while ((doshDest = FCREATE(pszOutFile)) == -1);
      else
      {
         // shut down the old output file
         FCLOSE(doshIn);
         FCLOSE(doshDest);
         if (remove(pszOutFile))
            printf(pszNO_DELETE_OLD, pszOutFile);
         printf(pszNOT_ENOUGH_DISK, chDrive);
         return(LZERROR_WRITE);
      }

      // check to see if some buffer data remains to be written
      if (ucbWritten > 0
          && _error == 0U)
      {
         // account for partial writes
         ucbToWrite -= ucbWritten;
         puchOutBuf += ucbWritten;
      }
   }

   cblOutSize += (long)ucbTotWritten;

   // add the next character to the buffer
   return((int)(*puchOutBuf++ = uch));
}  // WriteOutBuf()



// WriteHdr()
//
// Writes compressed file header to output file.  Could add fragment number
// to write in header as argument to WriteHdr().  The only error codes that
// may be returned are LZERROR_BADINHANDLE and LZERROR_BADOUTHANDLE.
//
// header format:
//                8 bytes  -->   compressed file signature
//                1 byte   -->   algorithm label
//                1 byte   -->   version id
//                4 bytes  -->   uncompressed file size (LSB to MSB)
//
//       total = 14 bytes
//
int WriteHdr(int doshDest)    // output file handle
{
   int i,
       f;            // writeUChar return value
   UCHAR uch;        // temporary storage for next header byte to write

   // move to beginning of output file
   if (doshDest != NO_DOSH && FSEEK(doshDest, 0L, SEEK_SET) != 0L)
      return((int)LZERROR_BADOUTHANDLE);

   // write the compressed file signature
   for (i = 0; i < cbCompSigLength; i++)
   {
      uch = (UCHAR)(*(szCompSig + i));
      if ((f = writeUChar(uch)) != (int)(uch))
         return(f);
   }

   // write out algorithm label and version number
   if ((f = writeUChar(uchAlgorithm)) != (int)uchAlgorithm)
      return(f);
   if ((f = writeUChar(uchVersion)) != (int)uchVersion)
      return(f);

   // write out input file size (long ==> 4 bytes)
   // LSB first, MSB last
   uch = (UCHAR)(cblInSize & CHAR_MASK);              // LSB
   if ((f = writeUChar(uch)) != (int)uch)
      return(f);
   uch = (UCHAR)((cblInSize >> 8) & CHAR_MASK);
   if ((f = writeUChar(uch)) != (int)uch)
      return(f);
   uch = (UCHAR)((cblInSize >> 16) & CHAR_MASK);
   if ((f = writeUChar(uch)) != (int)uch)
      return(f);
   uch = (UCHAR)((cblInSize >> 24) & CHAR_MASK);      // MSB
   if ((f = writeUChar(uch)) != (int)uch)
      return(f);

   return(WRITEHDR_OK);
}  // WriteHdr()

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -