cabinet.c

来自「一个类似windows」· C语言 代码 · 共 1,136 行 · 第 1/3 页

C
1,136
字号
/*
 * COPYRIGHT:   See COPYING in the top level directory
 * PROJECT:     ReactOS text-mode setup
 * FILE:        subsys/system/usetup/cabinet.c
 * PURPOSE:     Cabinet routines
 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
 * REVISIONS:
 *   CSH 15/08-2003 Created
 */

#include <usetup.h>
#include <zlib.h>

#define NDEBUG
#include <debug.h>

#define SEEK_BEGIN    0
#define SEEK_CURRENT  1
#ifndef SEEK_END
#define SEEK_END      2
#endif

typedef struct __DOSTIME
{
  WORD Second:5;
  WORD Minute:6;
  WORD Hour:5;
} DOSTIME, *PDOSTIME;


typedef struct __DOSDATE
{
  WORD Day:5;
  WORD Month:4;
  WORD Year:5;
} DOSDATE, *PDOSDATE;

static WCHAR CabinetName[256];          // Filename of current cabinet
static WCHAR CabinetPrev[256];          // Filename of previous cabinet
static WCHAR DiskPrev[256];             // Label of cabinet in file CabinetPrev
static WCHAR CabinetNext[256];          // Filename of next cabinet
static WCHAR DiskNext[256];             // Label of cabinet in file CabinetNext
static ULONG FolderUncompSize = 0;      // Uncompressed size of folder
static ULONG BytesLeftInBlock = 0;      // Number of bytes left in current block
static WCHAR DestPath[MAX_PATH];
static HANDLE FileHandle;
static HANDLE FileSectionHandle;
static PUCHAR FileBuffer;
static ULONG DestFileSize;
static ULONG FileSize;
static BOOL FileOpen = FALSE;
static PCFHEADER PCABHeader;
static PCFFOLDER CabinetFolders;
static ULONG CabinetReserved = 0;
static ULONG FolderReserved = 0;
static ULONG DataReserved = 0;
static ULONG CodecId;
static PCABINET_CODEC_UNCOMPRESS CodecUncompress = NULL;
static BOOL CodecSelected = FALSE;
static ULONG LastFileOffset = 0;          // Uncompressed offset of last extracted file
static PCABINET_OVERWRITE OverwriteHandler = NULL;
static PCABINET_EXTRACT ExtractHandler = NULL;
static PCABINET_DISK_CHANGE DiskChangeHandler = NULL;
static z_stream ZStream;
static PVOID CabinetReservedArea = NULL;


/* Needed by zlib, but we don't want the dependency on msvcrt.dll */

void __cdecl free(void* _ptr)
{
  RtlFreeHeap(ProcessHeap, 0, _ptr);
}

void* __cdecl calloc(size_t _nmemb, size_t _size)
{
  return (void*)RtlAllocateHeap (ProcessHeap, HEAP_ZERO_MEMORY, _size);
}

/* RAW codec */

ULONG
RawCodecUncompress(PVOID OutputBuffer,
				   PVOID InputBuffer,
				   PLONG InputLength,
				   PLONG OutputLength)
/*
 * FUNCTION: Uncompresses data in a buffer
 * ARGUMENTS:
 *     OutputBuffer = Pointer to buffer to place uncompressed data
 *     InputBuffer  = Pointer to buffer with data to be uncompressed
 *     InputLength  = Length of input buffer before, and amount consumed after
 *                    Negative to indicate that this is not the start of a new block
 *     OutputLength = Length of output buffer before, amount filled after
 *                    Negative to indicate that this is not the end of the block
 */
{
  LONG In = abs(*InputLength), Out = abs(*OutputLength);
  memcpy(OutputBuffer, InputBuffer, In < Out ? In : Out);
  *InputLength = *OutputLength = In < Out ? In : Out;
  return CS_SUCCESS;
}


/* MSZIP codec */

ULONG
MSZipCodecUncompress(PVOID OutputBuffer,
					 PVOID InputBuffer,
					 PLONG InputLength,
					 PLONG OutputLength)
/*
 * FUNCTION: Uncompresses data in a buffer
 * ARGUMENTS:
 *     OutputBuffer = Pointer to buffer to place uncompressed data
 *     InputBuffer  = Pointer to buffer with data to be uncompressed
 *     InputLength  = Length of input buffer before, and amount consumed after
 *                    Negative to indicate that this is not the start of a new block
 *     OutputLength = Length of output buffer before, amount filled after
 *                    Negative to indicate that this is not the end of the block
 */
{
  USHORT Magic;
  INT Status;

  DPRINT("MSZipCodecUncompress( OutputBuffer = %x, InputBuffer = %x, InputLength = %d, OutputLength = %d.\n", OutputBuffer, InputBuffer, *InputLength, *OutputLength);
  if( *InputLength > 0 )
	{
	  Magic = *((PUSHORT)InputBuffer);

	  if (Magic != MSZIP_MAGIC)
		{
		  DPRINT("Bad MSZIP block header magic (0x%X)\n", Magic);
		  return CS_BADSTREAM;
		}
	
	  ZStream.next_in   = (PUCHAR)((ULONG)InputBuffer + 2);
	  ZStream.avail_in  = *InputLength - 2;
	  ZStream.next_out  = (PUCHAR)OutputBuffer;
	  ZStream.avail_out = abs(*OutputLength);

	  /* WindowBits is passed < 0 to tell that there is no zlib header.
	   * Note that in this case inflate *requires* an extra "dummy" byte
	   * after the compressed stream in order to complete decompression and
	   * return Z_STREAM_END.
	   */
	  Status = inflateInit2(&ZStream, -MAX_WBITS);
	  if (Status != Z_OK)
		{
		  DPRINT("inflateInit2() returned (%d).\n", Status);
		  return CS_BADSTREAM;
		}
	  ZStream.total_in = 2;
	}
  else {
	ZStream.avail_in = -*InputLength;
	ZStream.next_in = (PUCHAR)InputBuffer;
	ZStream.next_out = (PUCHAR)OutputBuffer;
	ZStream.avail_out = abs(*OutputLength);
	ZStream.total_in = 0;
  }
  ZStream.total_out = 0;
  Status = inflate(&ZStream, Z_SYNC_FLUSH );
  if (Status != Z_OK && Status != Z_STREAM_END)
	{
	  DPRINT("inflate() returned (%d) (%s).\n", Status, ZStream.msg);
	  if (Status == Z_MEM_ERROR)
		return CS_NOMEMORY;
	  return CS_BADSTREAM;
	}

  if( *OutputLength > 0 )
	{
	  Status = inflateEnd(&ZStream);
	  if (Status != Z_OK)
		{
		  DPRINT("inflateEnd() returned (%d).\n", Status);
		  return CS_BADSTREAM;
		}
	}
  *OutputLength = ZStream.total_out;
  *InputLength = ZStream.total_in;
  return CS_SUCCESS;
}



/* Memory functions */

voidpf MSZipAlloc(voidpf opaque, uInt items, uInt size)
{
  return (voidpf)RtlAllocateHeap (ProcessHeap, 0, items * size);
}

void MSZipFree (voidpf opaque, voidpf address)
{
  RtlFreeHeap(ProcessHeap, 0, address);
}

static BOOL
ConvertSystemTimeToFileTime(
  CONST SYSTEMTIME *  lpSystemTime,	
  LPFILETIME  lpFileTime)
{
  TIME_FIELDS TimeFields;
  LARGE_INTEGER liTime;
  
  TimeFields.Year = lpSystemTime->wYear;
  TimeFields.Month = lpSystemTime->wMonth;
  TimeFields.Day = lpSystemTime->wDay;
  TimeFields.Hour = lpSystemTime->wHour;
  TimeFields.Minute = lpSystemTime->wMinute;
  TimeFields.Second = lpSystemTime->wSecond;
  TimeFields.Milliseconds = lpSystemTime->wMilliseconds;
  
  if (RtlTimeFieldsToTime(&TimeFields, &liTime))
    {
      lpFileTime->dwLowDateTime = liTime.u.LowPart;
      lpFileTime->dwHighDateTime = liTime.u.HighPart;
      return TRUE;
    }
  return FALSE;
}


static BOOL
ConvertDosDateTimeToFileTime(
  WORD wFatDate,
  WORD wFatTime,
  LPFILETIME lpFileTime)
{
  PDOSTIME  pdtime = (PDOSTIME) &wFatTime;
  PDOSDATE  pddate = (PDOSDATE) &wFatDate;
  SYSTEMTIME SystemTime;
  
  if (lpFileTime == NULL)
    return FALSE;
  
  SystemTime.wMilliseconds = 0;
  SystemTime.wSecond = pdtime->Second;
  SystemTime.wMinute = pdtime->Minute;
  SystemTime.wHour = pdtime->Hour;
  
  SystemTime.wDay = pddate->Day;
  SystemTime.wMonth = pddate->Month;
  SystemTime.wYear = 1980 + pddate->Year;
  
  ConvertSystemTimeToFileTime(&SystemTime,lpFileTime);
  
  return TRUE;
}


static PWCHAR
GetFileName(PWCHAR Path)
/*
 * FUNCTION: Returns a pointer to file name
 * ARGUMENTS:
 *     Path = Pointer to string with pathname
 * RETURNS:
 *     Pointer to filename
 */
{
  ULONG i, j;
  
  j = i = 0;
  
  while (Path [i++])
    {
      if (Path[i - 1] == L'\\') j = i;
    }
  return Path + j;
}


static VOID
RemoveFileName(PWCHAR Path)
/*
 * FUNCTION: Removes a file name from a path
 * ARGUMENTS:
 *     Path = Pointer to string with path
 */
{
  PWCHAR FileName;
  DWORD i;
  
  i = 0;
  FileName = GetFileName(Path + i);
  
  if ((FileName != (Path + i)) && (FileName [-1] == L'\\'))
    FileName--;
  if ((FileName == (Path + i)) && (FileName [0] == L'\\'))
    FileName++;
  FileName[0] = 0;
}


static BOOL
SetAttributesOnFile(PCFFILE File, HANDLE hFile)
/*
 * FUNCTION: Sets attributes on a file
 * ARGUMENTS:
 *      File = Pointer to CFFILE node for file
 * RETURNS:
 *     Status of operation
 */
{
  FILE_BASIC_INFORMATION FileBasic;
  IO_STATUS_BLOCK IoStatusBlock;
  NTSTATUS NtStatus;
  ULONG Attributes = 0;

  if (File->Attributes & CAB_ATTRIB_READONLY)
    Attributes |= FILE_ATTRIBUTE_READONLY;

  if (File->Attributes & CAB_ATTRIB_HIDDEN)
    Attributes |= FILE_ATTRIBUTE_HIDDEN;

  if (File->Attributes & CAB_ATTRIB_SYSTEM)
    Attributes |= FILE_ATTRIBUTE_SYSTEM;

  if (File->Attributes & CAB_ATTRIB_DIRECTORY)
    Attributes |= FILE_ATTRIBUTE_DIRECTORY;

  if (File->Attributes & CAB_ATTRIB_ARCHIVE)
    Attributes |= FILE_ATTRIBUTE_ARCHIVE;

  NtStatus = NtQueryInformationFile(hFile,
    &IoStatusBlock,
    &FileBasic,
    sizeof(FILE_BASIC_INFORMATION),
    FileBasicInformation);
  if (!NT_SUCCESS(NtStatus))
    {
      DPRINT("NtQueryInformationFile() failed (%x).\n", NtStatus);
    }
  else
    {
      FileBasic.FileAttributes = Attributes;

      NtStatus = NtSetInformationFile(hFile,
        &IoStatusBlock,
        &FileBasic,
        sizeof(FILE_BASIC_INFORMATION),
        FileBasicInformation);
      if (!NT_SUCCESS(NtStatus))
        {
          DPRINT("NtSetInformationFile() failed (%x).\n", NtStatus);
        }
    }

  return NT_SUCCESS(NtStatus);
}

static ULONG
CloseCabinet(VOID)
/*
 * FUNCTION: Closes the current cabinet
 * RETURNS:
 *     Status of operation
 */
{
  if (FileBuffer)
    {
      NtUnmapViewOfSection( NtCurrentProcess(), FileBuffer );
	  NtClose( FileSectionHandle );
	  NtClose( FileHandle );
      FileBuffer = NULL;
    }
  
  return 0;
}


VOID
CabinetInitialize(VOID)
/*
 * FUNCTION: Initialize archiver
 */

⌨️ 快捷键说明

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