/*++

Copyright (c) 1998  Microsoft Corporation

Module Name:

    compress.c

Abstract:

    This module contains the code to compress a file
    into a cab file.

Author:

    Wesley Witt (wesw) 29-Sept-1998

Revision History:

--*/

#include <ntcabp.h>
#pragma hdrstop



BOOL
NtCabCompressOneFile(
    IN PCAB_INSTANCE_DATA CabInst,
    IN PCWSTR FileName
    )
{
    NTSTATUS Status;
    HANDLE hFile;
    DWORD FileSize;
    DWORD Bytes = 0;
    DWORD BytesRead;
    DWORD BytesCompressed;
    DWORD Length = 0;
    PCAB_DIR_ENTRY CabDir;
    ULONG i;
    BY_HANDLE_FILE_INFORMATION fi;
    WCHAR ShortFileName[32];


    hFile = CreateFile(
        FileName,
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
        );
    if (hFile == INVALID_HANDLE_VALUE) {
        return GetLastError();
    }

    FileSize = GetFileSize( hFile, NULL );

    BytesRead = sizeof(CAB_DIR_ENTRY) + (sizeof(ULONG)*64);
    CabDir = (PCAB_DIR_ENTRY) malloc( BytesRead );
    if (CabDir == NULL) {
        return ERROR_NOT_ENOUGH_MEMORY;
    }

    ZeroMemory( CabDir, BytesRead );

    GetFileInformationByHandle( hFile, &fi );

    CabDir->FileAttributes = fi.dwFileAttributes;
    CabDir->CreationTime = fi.ftCreationTime;
    CabDir->LastAccessTime = fi.ftLastAccessTime;
    CabDir->LastWriteTime = fi.ftLastWriteTime;
    CabDir->FileSize = FileSize;
    if (MapFileAndCheckSum( (PWSTR)FileName, &i, &CabDir->ChkSum ) != CHECKSUM_SUCCESS) {
        CabDir->ChkSum = 0;
    }
    CabDir->Offset = SetFilePointer( CabInst->hCab, 0, NULL, FILE_CURRENT );
    if (GetShortPathName( FileName, ShortFileName, sizeof(ShortFileName)/sizeof(WCHAR) ) == 0) {
        return FALSE;
    }
    wcscpy( CabDir->FileName, ShortFileName );
    i = 0;

    while (Bytes < FileSize) {
        BytesRead = min( CabInst->ReadBufSize, FileSize-Bytes );
        Status = ReadFile(
            hFile,
            CabInst->ReadBuf,
            BytesRead,
            &BytesRead,
            NULL
            );
        Bytes += BytesRead;
        Status = RtlCompressBuffer(
            COMPRESSION_FLAGS,
            CabInst->ReadBuf,
            BytesRead,
            CabInst->CompressBuf,
            CabInst->CompressBufSize,
            4096,
            &BytesCompressed,
            CabInst->WorkSpace
            );
        Status = WriteFile(
            CabInst->hCab,
            CabInst->CompressBuf,
            BytesCompressed,
            &BytesRead,
            NULL
            );
        Length += BytesRead;
        CabDir->Segment[i++] = BytesRead;
        CabDir->CompressedFileSize += BytesRead;
    }

    CabDir->Segments = i;
    InsertTailList( &CabInst->CabDir, &CabDir->Next );

    CloseHandle( hFile );

    CabInst->CabNum += 1;

    return 0;
}