reactos/modules/rosapps/lib/vfdlib/vfdzip.c
Pierre Schweitzer 25c7e1a8d0
[VFD] Import the VFD project (Virtual Floppy Drive) which allows creating virtual
floppy drives in ReactOS and mount images on them.
Only the cmd got imported. The GUI interface may come later on.
Note that, as for vcdrom, the driver is left disabled and you need to explicitely
start it through vfd command line interface.

CORE-14090
2017-12-16 21:48:34 +01:00

423 lines
8.7 KiB
C

/*
vfdzip.c
Virtual Floppy Drive for Windows
Driver control library
Zip compressed floppy image handling
Copyright (C) 2003-2005 Ken Kato
*/
#ifdef __cplusplus
#pragma message(__FILE__": Compiled as C++ for testing purpose.")
#endif // __cplusplus
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "vfdtypes.h"
#include "vfdio.h"
#include "vfdlib.h"
#ifndef __REACTOS__
#define ZLIB_WINAPI
#else
#define Z_SOLO
#define ZLIB_INTERNAL
#endif
#include "zlib.h"
#ifdef VFD_NO_ZLIB
#pragma message("ZIP image support is disabled.")
DWORD ExtractZipInfo(
HANDLE hFile,
ULONG *pSize)
{
UNREFERENCED_PARAMETER(hFile);
UNREFERENCED_PARAMETER(pSize);
return ERROR_NOT_SUPPORTED;
}
DWORD ExtractZipImage(
HANDLE hFile,
PUCHAR *pBuffer,
PULONG pLength)
{
UNREFERENCED_PARAMETER(hFile);
UNREFERENCED_PARAMETER(pBuffer);
UNREFERENCED_PARAMETER(pLength);
return ERROR_NOT_SUPPORTED;
}
#else // VFD_NO_ZLIB
#ifdef _DEBUG
static const char *ZLIB_ERROR(int err)
{
switch (err) {
case Z_OK : return "Z_OK";
case Z_STREAM_END : return "Z_STREAM_END";
case Z_NEED_DICT : return "Z_NEED_DICT";
case Z_ERRNO : return "Z_ERRNO";
case Z_STREAM_ERROR : return "Z_STREAM_ERROR";
case Z_DATA_ERROR : return "Z_DATA_ERROR";
case Z_MEM_ERROR : return "Z_MEM_ERROR";
case Z_BUF_ERROR : return "Z_BUF_ERROR";
case Z_VERSION_ERROR: return "Z_VERSION_ERROR";
default : return "unknown";
}
}
#endif // _DEBUG
voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size))
{
UNREFERENCED_PARAMETER(opaque);
return LocalAlloc(LPTR, items * size);
}
void zcfree OF((voidpf opaque, voidpf ptr))
{
UNREFERENCED_PARAMETER(opaque);
LocalFree(ptr);
}
#define ZIP_LOCAL_SIGNATURE 0x04034b50
#define ZIP_FLAG_ENCRYPTED 0x01
#define ZIP_FLAG_DEFLATE_NORMAL 0x00
#define ZIP_FLAG_DEFLATE_MAX 0x02
#define ZIP_FLAG_DEFLATE_FAST 0x04
#define ZIP_FLAG_DEFLATE_SUPER 0x06
#define ZIP_FLAG_DEFLATE_MASK 0x06
#define ZIP_FLAG_SIZE_IN_DESC 0x08
#define ZIP_METHOD_STORED 0
#define ZIP_METHOD_SHRUNK 1
#define ZIP_METHOD_REDUCED1 2
#define ZIP_METHOD_REDUCED2 3
#define ZIP_METHOD_REDUCED3 4
#define ZIP_METHOD_REDUCED4 5
#define ZIP_METHOD_IMPLODED 6
#define ZIP_METHOD_TOKENIZED 7
#define ZIP_METHOD_DEFLATED 8
#define ZIP_METHOD_DEFLATE64 9
#define ZIP_METHOD_PKWARE_IMP 10
#define ZIP_METHOD_RESERVED 11
#define ZIP_METHOD_BZIP2 12
#pragma pack(1)
typedef struct _zip_local_file_header {
ULONG header_signature;
USHORT required_version;
USHORT general_flags;
USHORT compression_method;
USHORT last_mod_time;
USHORT last_mod_date;
ULONG crc32;
ULONG compressed_size;
ULONG uncompressed_size;
USHORT file_name_length;
USHORT extra_field_length;
CHAR file_name[1];
// followed by extra field data, then compressed data
}
ZIP_HEADER, *PZIP_HEADER;
//
// Check if the file is ZIP compressed
//
DWORD ExtractZipInfo(
HANDLE hFile,
ULONG *pSize)
{
ZIP_HEADER zip_hdr;
DWORD result;
DWORD ret;
if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) != 0) {
ret = GetLastError();
VFDTRACE(0,
("SetFilePointer() - %s\n",
SystemMessage(ret)));
return ret;
}
if (!ReadFile(hFile, &zip_hdr, sizeof(zip_hdr), &result, NULL)) {
ret = GetLastError();
VFDTRACE(0,
("ReadFile() - %s\n",
SystemMessage(ret)));
return ret;
}
if (result != sizeof(zip_hdr) ||
zip_hdr.header_signature != ZIP_LOCAL_SIGNATURE ||
zip_hdr.compression_method != ZIP_METHOD_DEFLATED ||
(zip_hdr.general_flags & ZIP_FLAG_ENCRYPTED)) {
VFDTRACE(0,
("[VFD] Invalid ZIP file\n"));
return ERROR_INVALID_DATA;
}
// correct (and supported) ZIP header detected
*pSize = zip_hdr.uncompressed_size;
return ERROR_SUCCESS;
}
//
// Extract original data from IMZ file
//
DWORD ExtractZipImage(
HANDLE hFile,
PUCHAR *pBuffer,
PULONG pLength)
{
UCHAR buf[VFD_BYTES_PER_SECTOR];
DWORD result;
DWORD ret;
PZIP_HEADER zip_hdr;
ULONG compressed;
ULONG uncompressed;
PUCHAR file_cache;
z_stream stream;
int zlib_ret;
VFDTRACE(0,
("[VFD] VfdExtractImz - IN\n"));
*pBuffer = NULL;
*pLength = 0;
//
// Read PKZIP local file header of the first file in the file
// -- An IMZ file actually is just a ZIP file with a different
// extension, which contains a single floppy image file
//
if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) != 0) {
ret = GetLastError();
VFDTRACE(0,(
"SetFilePointer - %s", SystemMessage(ret)));;
return ret;
}
if (!ReadFile(hFile, buf, VFD_BYTES_PER_SECTOR, &result, NULL) ||
result < VFD_BYTES_PER_SECTOR) {
ret = GetLastError();
VFDTRACE(0,(
"ReadFile - %s", SystemMessage(ret)));;
return ret;
}
zip_hdr = (PZIP_HEADER)buf;
// check local file header signature
if (zip_hdr->header_signature != ZIP_LOCAL_SIGNATURE) {
VFDTRACE(0,
("[VFD] PKZIP header signature not found.\n"));
return ERROR_INVALID_DATA;
}
// check compression method
if (zip_hdr->compression_method != Z_DEFLATED) {
VFDTRACE(0,
("[VFD] Bad PKZIP compression method.\n"));
return ERROR_NOT_SUPPORTED;
}
if (zip_hdr->general_flags & 0x01) {
// encrypted zip not supported
VFDTRACE(0,
("[VFD] PKZIP encrypted.\n"));
return ERROR_NOT_SUPPORTED;
}
// check uncompressed image size
compressed = zip_hdr->compressed_size;
uncompressed = zip_hdr->uncompressed_size;
switch (uncompressed) {
case VFD_SECTOR_TO_BYTE(320):
case VFD_SECTOR_TO_BYTE(360):
case VFD_SECTOR_TO_BYTE(640):
case VFD_SECTOR_TO_BYTE(720):
case VFD_SECTOR_TO_BYTE(1280):
case VFD_SECTOR_TO_BYTE(1440):
case VFD_SECTOR_TO_BYTE(1640):
case VFD_SECTOR_TO_BYTE(2400):
case VFD_SECTOR_TO_BYTE(2880):
case VFD_SECTOR_TO_BYTE(3360):
case VFD_SECTOR_TO_BYTE(3444):
case VFD_SECTOR_TO_BYTE(5760):
break;
default:
VFDTRACE(0,
("[VFD] Unsupported image size %lu.\n",
uncompressed));
return ERROR_NOT_SUPPORTED;
}
// check local file header length
// -- Just for simplicity, the compressed data must start in the
// first sector in the file: this is not a problem in most cases.
if (FIELD_OFFSET(ZIP_HEADER, file_name) +
zip_hdr->file_name_length +
zip_hdr->extra_field_length >= VFD_BYTES_PER_SECTOR) {
VFDTRACE(0,
("[VFD] PKZIP header too long.\n"));
return ERROR_NOT_SUPPORTED;
}
// allocate memory to store uncompressed data
file_cache = (PUCHAR)LocalAlloc(LPTR, uncompressed);
if (!file_cache) {
VFDTRACE(0,
("[VFD] Failed to allocate file cache.\n"));
return ERROR_OUTOFMEMORY;
}
// initialize the zlib stream
ZeroMemory(&stream, sizeof(stream));
// set initial input data information
stream.next_in = (PUCHAR)zip_hdr->file_name +
zip_hdr->file_name_length + zip_hdr->extra_field_length;
stream.avail_in = VFD_BYTES_PER_SECTOR -
FIELD_OFFSET(ZIP_HEADER, file_name) -
zip_hdr->file_name_length - zip_hdr->extra_field_length;
// set output buffer information
stream.next_out = file_cache;
stream.avail_out = uncompressed;
zlib_ret = inflateInit2(&stream, -MAX_WBITS);
// negative MAX_WBITS value passed to the inflateInit2() function
// indicates that there is no zlib header.
// In this case inflate() function requires an extra "dummy" byte
// after the compressed stream in order to complete decompression
// and return Z_STREAM_END. However, both compressed and uncompressed
// data size are already known from the pkzip header, Z_STREAM_END
// is not absolutely necessary to know the completion of the operation.
if (zlib_ret != Z_OK) {
LocalFree(file_cache);
VFDTRACE(0,
("[VFD] inflateInit2() failed - %s.\n",
ZLIB_ERROR(zlib_ret)));
return ERROR_INVALID_FUNCTION;
}
for (;;) {
// uncompress current block
zlib_ret = inflate(&stream, Z_NO_FLUSH);
if (zlib_ret != Z_OK) {
if (zlib_ret == Z_STREAM_END) {
ret = ERROR_SUCCESS;
}
else {
VFDTRACE(0,
("[VFD] inflate() failed - %s.\n",
ZLIB_ERROR(zlib_ret)));
ret = ERROR_INVALID_FUNCTION;
}
break;
}
if (stream.total_out >= uncompressed) {
// uncompress completed - no need to wait for Z_STREAM_END
// (inflate() would return Z_STREAM_END on the next call)
ret = ERROR_SUCCESS;
break;
}
if (stream.total_in >= compressed) {
// somehow there is not enought compressed data
ret = ERROR_INVALID_FUNCTION;
break;
}
// read next block from file
if (!ReadFile(hFile, buf, VFD_BYTES_PER_SECTOR, &result, NULL) ||
result <= 0) {
ret = GetLastError();
VFDTRACE(0,
("[VFD] Read compressed data - %s.\n",
SystemMessage(ret)));
break;
}
stream.avail_in = result;
stream.next_in = buf;
}
// cleanup the zlib stream
inflateEnd(&stream);
// set the return information
if (ret == ERROR_SUCCESS) {
*pBuffer = file_cache;
*pLength = uncompressed;
}
else {
LocalFree(file_cache);
}
VFDTRACE(0,
("[VFD] VfdExtractImz - OUT\n"));
return ret;
}
#endif // VFD_NO_ZLIB