mirror of https://github.com/PCSX2/pcsx2.git
411 lines
12 KiB
C
411 lines
12 KiB
C
/* gzipv1.c
|
|
* Copyright (C) 2002-2005 PCSX2 Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* PCSX2 members can be contacted through their website at www.pcsx2.net.
|
|
*/
|
|
|
|
#include <stddef.h> // NULL
|
|
|
|
#include "zlib/zlib.h"
|
|
|
|
#include "convert.h"
|
|
#include "logfile.h"
|
|
#include "isofile.h"
|
|
#include "isocompress.h" // TableData
|
|
#include "actualfile.h"
|
|
#include "gzipv1.h"
|
|
|
|
#ifdef _WIN32
|
|
#pragma pack(1)
|
|
#endif /* _WIN32 */
|
|
|
|
struct GZipV1Table
|
|
{
|
|
unsigned int offset; // Data file position
|
|
unsigned short size; // of Compressed data
|
|
#ifdef _WIN32
|
|
};
|
|
#else
|
|
} __attribute__((packed));
|
|
#endif /* _WIN32 */
|
|
#ifdef _WIN32
|
|
#pragma pack()
|
|
#endif /* _WIN32 */
|
|
|
|
int GZipV1OpenTableForRead(struct IsoFile *isofile)
|
|
{
|
|
int i;
|
|
int j;
|
|
char tableext[] = ".table\0";
|
|
#ifdef VERBOSE_FUNCTION_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: OpenTableForRead()");
|
|
#endif /* VERBOSE_FUNCTION_GZIPV1 */
|
|
i = 0;
|
|
while ((i < 256) && (isofile->name[i] != 0))
|
|
{
|
|
isofile->tablename[i] = isofile->name[i];
|
|
i++;
|
|
} // ENDWHILE- Copying the data name to the table name
|
|
j = 0;
|
|
while ((i < 256) && (tableext[j] != 0))
|
|
{
|
|
isofile->tablename[i] = tableext[j];
|
|
i++;
|
|
j++;
|
|
} // ENDWHILE- Adding the ".table" extension.
|
|
isofile->tablename[i] = 0; // And 0-terminate.
|
|
|
|
isofile->tablehandle = ActualFileOpenForRead(isofile->tablename);
|
|
if (isofile->tablehandle == ACTUALHANDLENULL)
|
|
{
|
|
#ifdef VERBOSE_WARNING_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Couldn't open table!");
|
|
#endif /* VERBOSE_WARNING_GZIPV1 */
|
|
return(-2);
|
|
} // ENDIF- Couldn't open table file? Fail.
|
|
|
|
isofile->filesectorsize = ActualFileSize(isofile->tablehandle)
|
|
/ sizeof(struct GZipV1Table);
|
|
return(0);
|
|
} // END GZipV1OpenTableForRead()
|
|
|
|
int GZipV1SeekTable(struct IsoFile *isofile, off64_t sector)
|
|
{
|
|
off64_t target;
|
|
int retval;
|
|
#ifdef VERBOSE_FUNCTION_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: SeekTable(%lli)", sector);
|
|
#endif /* VERBOSE_FUNCTION_GZIPV1 */
|
|
target = sector * sizeof(struct GZipV1Table);
|
|
retval = ActualFileSeek(isofile->tablehandle, target);
|
|
if (retval < 0)
|
|
{
|
|
#ifdef VERBOSE_WARNING_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Couldn't find sector!");
|
|
#endif /* VERBOSE_WARNING_GZIPV1 */
|
|
return(-2);
|
|
} // ENDIF- Trouble finding the place? Fail.
|
|
|
|
isofile->filesectorpos = sector;
|
|
return(0);
|
|
} // END GZipV1SeekTable()
|
|
|
|
int GZipV1ReadTable(struct IsoFile *isofile, struct TableData *table)
|
|
{
|
|
int retval;
|
|
struct GZipV1Table temptable;
|
|
#ifdef VERBOSE_FUNCTION_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: ReadTable()");
|
|
#endif /* VERBOSE_FUNCTION_GZIPV1 */
|
|
retval = ActualFileRead(isofile->tablehandle,
|
|
sizeof(struct GZipV1Table),
|
|
(char *) & temptable);
|
|
if (retval != sizeof(struct GZipV1Table))
|
|
{
|
|
#ifdef VERBOSE_WARNING_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Couldn't read table entry!");
|
|
#endif /* VERBOSE_WARNING_GZIPV1 */
|
|
return(-2);
|
|
} // ENDIF- Trouble reading table entry? Fail.
|
|
table->offset = ConvertEndianUInt(temptable.offset);
|
|
table->size = ConvertEndianUShort(temptable.size);
|
|
isofile->filesectorpos++;
|
|
return(0);
|
|
} // END GZipV1ReadTable()
|
|
|
|
int GZipV1OpenTableForWrite(struct IsoFile *isofile)
|
|
{
|
|
int i;
|
|
int j;
|
|
char tableext[] = ".table\0";
|
|
#ifdef VERBOSE_FUNCTION_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: OpenTableForWrite()");
|
|
#endif /* VERBOSE_FUNCTION_GZIPV1 */
|
|
i = 0;
|
|
while ((i < 256) && (isofile->name[i] != 0))
|
|
{
|
|
isofile->tablename[i] = isofile->name[i];
|
|
i++;
|
|
} // ENDWHILE- Copying the data name to the table name
|
|
j = 0;
|
|
while ((i < 256) && (tableext[j] != 0))
|
|
{
|
|
isofile->tablename[i] = tableext[j];
|
|
i++;
|
|
j++;
|
|
} // ENDWHILE- Adding the ".table" extension.
|
|
isofile->tablename[i] = 0; // And 0-terminate.
|
|
|
|
isofile->tablehandle = ActualFileOpenForWrite(isofile->tablename);
|
|
if (isofile->tablehandle == ACTUALHANDLENULL)
|
|
{
|
|
#ifdef VERBOSE_WARNING_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Couldn't open table!");
|
|
#endif /* VERBOSE_WARNING_GZIPV1 */
|
|
return(-2);
|
|
} // ENDIF- Couldn't open table file? Fail.
|
|
|
|
isofile->filesectorsize = 0;
|
|
return(0);
|
|
} // END GZipV1OpenTableForWrite()
|
|
|
|
int GZipV1WriteTable(struct IsoFile *isofile, struct TableData table)
|
|
{
|
|
int retval;
|
|
struct GZipV1Table temptable;
|
|
unsigned int tempint;
|
|
|
|
#ifdef VERBOSE_FUNCTION_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: WriteTable(%lli, %i)", table.offset, table.size);
|
|
#endif /* VERBOSE_FUNCTION_GZIPV1 */
|
|
|
|
tempint = table.offset;
|
|
temptable.offset = ConvertEndianUInt(tempint);
|
|
temptable.size = ConvertEndianUShort(table.size);
|
|
retval = ActualFileWrite(isofile->tablehandle,
|
|
sizeof(struct GZipV1Table),
|
|
(char *) & temptable);
|
|
if (retval != sizeof(struct GZipV1Table))
|
|
{
|
|
#ifdef VERBOSE_WARNING_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Couldn't write table entry!");
|
|
#endif /* VERBOSE_WARNING_GZIPV1 */
|
|
return(-2);
|
|
} // ENDIF- Trouble reading table entry? Fail.
|
|
return(0);
|
|
} // END GZipV1WriteTable()
|
|
|
|
int GZipV1OpenForRead(struct IsoFile *isofile)
|
|
{
|
|
int retval;
|
|
char tempblock[2448];
|
|
#ifdef VERBOSE_FUNCTION_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: OpenForRead()");
|
|
#endif /* VERBOSE_FUNCTION_GZIPV1 */
|
|
isofile->handle = ActualFileOpenForRead(isofile->name);
|
|
if (isofile->handle == ACTUALHANDLENULL)
|
|
{
|
|
return(-1);
|
|
} // ENDIF- Couldn't open data file? Fail.
|
|
|
|
isofile->filebytesize = ActualFileSize(isofile->handle);
|
|
isofile->filebytepos = 0;
|
|
isofile->filesectorpos = 0;
|
|
|
|
isofile->imageheader = 0;
|
|
isofile->blocksize = 2352;
|
|
isofile->blockoffset = 0; // Don't panic. "imagetype.c" will test later.
|
|
isofile->numsectors = 1; // Sectors per block
|
|
retval = GZipV1Read(isofile, 2448, tempblock);
|
|
if (retval != 0)
|
|
{
|
|
#ifdef VERBOSE_WARNING_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Couldn't decode the first block. Not compressed?");
|
|
#endif /* VERBOSE_WARNING_GZIPV1 */
|
|
ActualFileClose(isofile->handle);
|
|
isofile->handle = ACTUALHANDLENULL;
|
|
return(-1);
|
|
} // ENDIF Could not read the first sector? Fail.
|
|
ActualFileSeek(isofile->handle, 0); // Restart at top of file
|
|
isofile->filebytepos = 0;
|
|
isofile->filesectorpos = 0;
|
|
return(0);
|
|
} // END GZipV1OpenForRead()
|
|
|
|
int GZipV1Seek(struct IsoFile *isofile, off64_t position)
|
|
{
|
|
int retval;
|
|
#ifdef VERBOSE_FUNCTION_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Seek(%lli)", position);
|
|
#endif /* VERBOSE_FUNCTION_GZIPV1 */
|
|
retval = ActualFileSeek(isofile->handle, position);
|
|
if (retval < 0)
|
|
{
|
|
#ifdef VERBOSE_WARNING_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Couldn't find the start of the compressed block!");
|
|
#endif /* VERBOSE_WARNING_GZIPV1 */
|
|
return(-1);
|
|
} // ENDIF- Couldn't find the data entry? Fail.
|
|
isofile->filebytepos = position;
|
|
return(0);
|
|
return(-1); // Fail. (Due to lack of ambition?)
|
|
} // END GZipV1Seek()
|
|
|
|
int GZipV1Read(struct IsoFile *isofile, int bytes, char *buffer)
|
|
{
|
|
int retval;
|
|
unsigned long blocklen;
|
|
z_stream strm;
|
|
unsigned long tempin;
|
|
char tempblock[2800];
|
|
unsigned long tempout;
|
|
#ifdef VERBOSE_FUNCTION_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Read(%i)", bytes);
|
|
#endif /* VERBOSE_FUNCTION_GZIPV1 */
|
|
if (bytes > 0)
|
|
{
|
|
retval = ActualFileRead(isofile->handle, bytes, tempblock);
|
|
if (retval > 0) isofile->filebytepos += retval;
|
|
if (retval != bytes)
|
|
{
|
|
#ifdef VERBOSE_WARNING_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Cannot read bytes! Returned: (%i)", retval);
|
|
#endif /* VERBOSE_WARNING_GZIPV1 */
|
|
return(-1);
|
|
} // ENDIF- Trouble reading compressed sector? Abort.
|
|
blocklen = isofile->blocksize;
|
|
retval = uncompress(buffer, &blocklen, tempblock, bytes);
|
|
if (retval != Z_OK)
|
|
{
|
|
#ifdef VERBOSE_WARNING_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Cannot decode block! Returned: (%i)", retval);
|
|
#endif /* VERBOSE_WARNING_GZIPV1 */
|
|
return(-1);
|
|
} // ENDIF- Trouble decoding the sector? Abort.
|
|
|
|
return(0);
|
|
} // ENDIF- Do we know how many compressed bytes to get for this record?
|
|
// Hmm. Don't know the compressed size? Well, we'll just have to find it.
|
|
tempin = 0;
|
|
tempout = 0;
|
|
retval = Z_OK;
|
|
while ((tempin < 2800) && (tempout < 2352))
|
|
{
|
|
|
|
strm.zalloc = (alloc_func)0;
|
|
strm.zfree = (free_func)0;
|
|
strm.next_in = tempblock;
|
|
strm.next_out = buffer;
|
|
|
|
strm.avail_in = tempin;
|
|
strm.avail_out = 2800;
|
|
retval = inflateInit(&strm);
|
|
if (retval != Z_OK) return(-1);
|
|
|
|
while ((tempin < 2800) && (retval == Z_OK))
|
|
{
|
|
retval = ActualFileRead(isofile->handle, 1, &tempblock[tempin]);
|
|
if (retval != 1)
|
|
{
|
|
#ifdef VERBOSE_WARNING_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Cannot read a byte! Returned: (%i)", retval);
|
|
#endif /* VERBOSE_WARNING_GZIPV1 */
|
|
return(-1);
|
|
} // ENDIF- Trouble reading compressed sector? Abort.
|
|
tempin++;
|
|
strm.avail_in++;
|
|
strm.next_in = &tempblock[tempin - strm.avail_in];
|
|
retval = inflate(&strm, Z_NO_FLUSH);
|
|
} // ENDWHILE- trying to uncompress an increasingly filled buffer
|
|
tempout = strm.total_out;
|
|
inflateEnd(&strm);
|
|
#ifdef VERBOSE_FUNCTION_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: tempin=%lu tempout=%lu retval=%i",
|
|
tempin, tempout, retval);
|
|
#endif /* VERBOSE_FUNCTION_GZIPV1 */
|
|
} // ENDWHILE- trying to uncompress a whole buffer
|
|
if (retval != Z_STREAM_END)
|
|
{
|
|
#ifdef VERBOSE_WARNING_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Failed to decode block! Returned: (%i)", retval);
|
|
#endif /* VERBOSE_WARNING_GZIPV1 */
|
|
return(-1);
|
|
} // ENDIF- Trouble reading compressed sector? Abort.
|
|
if (tempin == 2800)
|
|
{
|
|
#ifdef VERBOSE_WARNING_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Overfilled input buffer for only %llu bytes!", tempout);
|
|
#endif /* VERBOSE_WARNING_GZIPV1 */
|
|
return(-1);
|
|
} // ENDIF- Trouble reading compressed sector? Abort.
|
|
isofile->filebytepos += tempin;
|
|
return(tempin); // Send out # of compressed bytes (to record in table)
|
|
} // END GZipV1Read()
|
|
|
|
int GZipV1OpenForWrite(struct IsoFile *isofile)
|
|
{
|
|
if (isofile == NULL) return(-1);
|
|
#ifdef VERBOSE_FUNCTION_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: OpenForWrite()");
|
|
#endif /* VERBOSE_FUNCTION_GZIPV1 */
|
|
isofile->handle = ActualFileOpenForWrite(isofile->name);
|
|
if (isofile->handle == ACTUALHANDLENULL)
|
|
{
|
|
return(-1);
|
|
} // ENDIF- Couldn't open data file? Fail.
|
|
|
|
isofile->filebytesize = 0;
|
|
isofile->filebytepos = 0;
|
|
return(0);
|
|
} // END GZipV1OpenForWrite()
|
|
|
|
int GZipV1Write(struct IsoFile *isofile, char *buffer)
|
|
{
|
|
int retval;
|
|
unsigned long blocklen;
|
|
char tempblock[2800];
|
|
#ifdef VERBOSE_FUNCTION_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Write()");
|
|
#endif /* VERBOSE_FUNCTION_GZIPV1 */
|
|
blocklen = 2800;
|
|
retval = compress2(tempblock, &blocklen,
|
|
buffer, 2352,
|
|
Z_BEST_COMPRESSION);
|
|
if (retval != Z_OK)
|
|
{
|
|
#ifdef VERBOSE_FUNCTION_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Cannot encode block! Returned: (%i)", retval);
|
|
#endif /* VERBOSE_FUNCTION_GZIPV1 */
|
|
return(-1);
|
|
} // ENDIF- Trouble compressing a block? Abort.
|
|
|
|
retval = ActualFileWrite(isofile->handle, blocklen, tempblock);
|
|
if (retval > 0) isofile->filebytepos += retval;
|
|
if (retval < blocklen)
|
|
{
|
|
#ifdef VERBOSE_FUNCTION_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Cannot write bytes! Returned: (%i out of %llu)",
|
|
retval, blocklen);
|
|
#endif /* VERBOSE_FUNCTION_GZIPV1 */
|
|
return(-1);
|
|
} // ENDIF- Trouble writing out the compressed block? Abort.
|
|
isofile->filesectorpos++;
|
|
return(blocklen);
|
|
} // END GZipV1Write()
|
|
|
|
void GZipV1Close(struct IsoFile *isofile)
|
|
{
|
|
#ifdef VERBOSE_FUNCTION_GZIPV1
|
|
PrintLog("CDVDiso GZipV1: Close()");
|
|
#endif /* VERBOSE_FUNCTION_GZIPV1 */
|
|
|
|
// Flush Write data... if any was held in the compression block area.
|
|
// In this case, though... nothing's held there.
|
|
if (isofile->tablehandle != ACTUALHANDLENULL)
|
|
{
|
|
ActualFileClose(isofile->tablehandle);
|
|
isofile->tablehandle = ACTUALHANDLENULL;
|
|
} // ENDIF- Is there a table file open? Close it.
|
|
|
|
if (isofile->handle != ACTUALHANDLENULL)
|
|
{
|
|
ActualFileClose(isofile->handle);
|
|
isofile->handle = ACTUALHANDLENULL;
|
|
} // ENDIF- Is there a data file open? Close it.
|
|
return;
|
|
} // END GZipV1Close()
|