326 lines
14 KiB
C++
326 lines
14 KiB
C++
//
|
|
// Copyright 2020 Electronic Arts Inc.
|
|
//
|
|
// TiberianDawn.DLL and RedAlert.dll and corresponding source code 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 3 of the License, or (at your option) any later version.
|
|
|
|
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
|
|
// in the hope that it will be useful, but with permitted additional restrictions
|
|
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
|
|
// distributed with this program. You should have received a copy of the
|
|
// GNU General Public License along with permitted additional restrictions
|
|
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
|
|
|
|
/***************************************************************************
|
|
** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
|
|
***************************************************************************
|
|
* *
|
|
* Project Name : Westwood Library *
|
|
* *
|
|
* File Name : IFF.C *
|
|
* *
|
|
* Programmer : Joe L. Bostic *
|
|
* *
|
|
* Start Date : May 16, 1991 *
|
|
* *
|
|
* Last Update : April 19, 1994 [SKB] *
|
|
* *
|
|
* *
|
|
* IFF reader code designed for loading pictures (ILBM or PBM). *
|
|
* *
|
|
*-------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* Close_Iff_File -- Closes an IFF file handle. *
|
|
* Get_Iff_Chunk_Size -- Get the size of the given IFF chunk. *
|
|
* Open_Iff_File -- Opens an IFF file for reading. *
|
|
* Read_Iff_Chunk -- Reads a chunk from an IFF file. *
|
|
* Write_Iff_Chunk -- Writes an IFF chuck out. *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
#include "iff.h"
|
|
#include "file.h"
|
|
|
|
#define ID_FORM MAKE_ID('F','O','R','M')
|
|
|
|
#ifdef MIN
|
|
#undef MIN
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
* OPEN_IFF_FILE -- Opens an IFF file for reading. *
|
|
* *
|
|
* This function will open an IFF file for reading. It will perform *
|
|
* a the simple validity test of checking the first four bytes to make *
|
|
* sure they are "FORM". The value returned is the filehandle of the *
|
|
* opened file. *
|
|
* *
|
|
* INPUT: filename - ASCII name of the IFF file to be opened. *
|
|
* *
|
|
* OUTPUT: Returns the filehandle. If there is an error or the file *
|
|
* is not an IFF FORM then -1 will be returned. *
|
|
* *
|
|
* WARNINGS: You are responsible for error handling if this function *
|
|
* returns -1 (not an IFF file). *
|
|
* *
|
|
* HISTORY: *
|
|
* 05/16/1991 JLB : Created. *
|
|
* 04/19/1994 SKB : Update to 32 bit library. *
|
|
*=========================================================================*/
|
|
int __cdecl Open_Iff_File(char const *filename)
|
|
{
|
|
int fh; // File handle.
|
|
long type; // IFF file type.
|
|
|
|
|
|
/* We want to be able to open the file for READ | WRITE, but we do not
|
|
want the Open_File to create it. So check to see if it exists before
|
|
the Open_File */
|
|
|
|
// fh = Open_File(filename, READ); // Open the source file for READ
|
|
// Close_File(fh);
|
|
|
|
//fh = Open_File(filename, READ | WRITE); // Open the source file again
|
|
fh = Open_File(filename, READ); // Open the source file again
|
|
|
|
// Validate that it is a FORM type.
|
|
|
|
Read_File(fh, &type, 4L);
|
|
|
|
if (type == ID_FORM) {
|
|
|
|
// The file is valid (so far). Position the read so that the actual
|
|
// IFF file type code can be read.
|
|
|
|
Seek_File(fh, 4L, SEEK_CUR); // Skip the filesize bytes.
|
|
|
|
} else {
|
|
|
|
// This is NOT an IFF file. Close the source file and return with
|
|
// the error code.
|
|
Close_File(fh);
|
|
fh = WW_ERROR;
|
|
}
|
|
return fh;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* CLOSE_IFF_FILE -- Closes an IFF file handle. *
|
|
* *
|
|
* The routine will close the file that was opened with the *
|
|
* Open_Iff_File() function. *
|
|
* *
|
|
* INPUT: fh - File handle that was returned from Open_Iff_File(). *
|
|
* *
|
|
* OUTPUT: none *
|
|
* *
|
|
* WARNINGS: none *
|
|
* *
|
|
* HISTORY: *
|
|
* 05/16/1991 JLB : Created. *
|
|
* 04/19/1994 SKB : Update to 32 bit library. *
|
|
*=========================================================================*/
|
|
void __cdecl Close_Iff_File(int fh)
|
|
{
|
|
if (fh != WW_ERROR) Close_File(fh);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* GET_IFF_CHUNK_SIZE -- Get the size of the given IFF chunk. *
|
|
* *
|
|
* INPUT: int file handle to open IFF file, long id to get size of *
|
|
* *
|
|
* OUTPUT: long size of the chunk or 0L if it was not found *
|
|
* *
|
|
* WARNINGS: none *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/03/1991 CY : Created. *
|
|
* 04/19/1994 SKB : Update to 32 bit library. *
|
|
*=========================================================================*/
|
|
unsigned long __cdecl Get_Iff_Chunk_Size(int fh, long id)
|
|
{
|
|
long form; // Chunk iff form name.
|
|
long chunksize; // Size of the chunk.
|
|
char first_iteration; // Check once the current chunk name
|
|
|
|
|
|
first_iteration = TRUE;
|
|
|
|
for (;;) {
|
|
if (Read_File(fh, &form, 4L) != 4L && !first_iteration) break;
|
|
|
|
|
|
if (Read_File(fh, (char *) &chunksize, 4L) != 4L && !first_iteration) break;
|
|
|
|
#if(IBM)
|
|
chunksize = Reverse_Long(chunksize);
|
|
#endif
|
|
|
|
if (id == form) {
|
|
Seek_File(fh, -8L, SEEK_CUR); // Seek back to the start of
|
|
return(chunksize); // the chunk & return size
|
|
} else {
|
|
|
|
if (first_iteration) {
|
|
Seek_File(fh, 12L, SEEK_SET); // Start at beginning of file.
|
|
first_iteration = FALSE; // Don't do this again
|
|
} else {
|
|
|
|
/* Otherwise, go to the next chunk in the file */
|
|
|
|
chunksize = (chunksize + 1) & 0xFFFFFFFEL;
|
|
Seek_File(fh, chunksize, SEEK_CUR);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(0L);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* READ_IFF_CHUNK -- Reads a chunk from an IFF file. *
|
|
* *
|
|
* Once an IFF file is opened, various chunks must be read from it. *
|
|
* This routine will search through the IFF file and load in the *
|
|
* specified chunk. It will scan through the entire file when *
|
|
* searching for the chunk. It will load the FIRST chunk of the given *
|
|
* type. *
|
|
* *
|
|
* INPUT: fh - File handle of IFF file. *
|
|
* *
|
|
* id - Chunk ID code. *
|
|
* *
|
|
* buffer - Pointer to buffer to load the chunk. *
|
|
* *
|
|
* maxsize - Maximum data bytes to read. *
|
|
* *
|
|
* OUTPUT: Returns with the number of bytes read from the chunk. *
|
|
* If 0 is returned, this indicates that the chunk wasn't *
|
|
* found. *
|
|
* *
|
|
* WARNINGS: none *
|
|
* *
|
|
* HISTORY: *
|
|
* 05/16/1991 JLB : Created. *
|
|
* 04/19/1994 SKB : Update to 32 bit library. *
|
|
*=========================================================================*/
|
|
unsigned long __cdecl Read_Iff_Chunk(int fh, long id, void *buffer, unsigned long maxsize)
|
|
{
|
|
long form; // Chunk iff form name.
|
|
unsigned long chunksize; // Size of the chunk.
|
|
char first_iteration; // Check once the current chunk name
|
|
|
|
first_iteration = TRUE;
|
|
|
|
for (;;) {
|
|
if (Read_File(fh, &form, 4L) != 4L && !first_iteration) break;
|
|
|
|
if (Read_File(fh, (char *) &chunksize, 4L) != 4L && !first_iteration) break;
|
|
|
|
#if(IBM)
|
|
chunksize = Reverse_Long(chunksize);
|
|
#endif
|
|
|
|
if (id == form) {
|
|
|
|
maxsize = MIN(maxsize, chunksize);
|
|
Read_File(fh, buffer, maxsize); // Read the buffer.
|
|
|
|
chunksize = (chunksize + 1) & 0xFFFFFFFEL;
|
|
if (maxsize < chunksize) {
|
|
Seek_File(fh, chunksize - maxsize, SEEK_CUR);
|
|
}
|
|
return(maxsize);
|
|
} else {
|
|
|
|
if (first_iteration) {
|
|
Seek_File(fh, 12L, SEEK_SET); // Start at beginning of file.
|
|
first_iteration = FALSE; // Don't do this again
|
|
|
|
} else {
|
|
|
|
/* Otherwise, go to the next chunk in the file */
|
|
|
|
chunksize = (chunksize + 1) & 0xFFFFFFFEL;
|
|
Seek_File(fh, chunksize, SEEK_CUR);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(0L);
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
* WRITE_IFF_CHUNK -- Writes an IFF chuck out. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 04/19/1994 SKB : Created. *
|
|
*=========================================================================*/
|
|
void __cdecl Write_Iff_Chunk(int file, long id, void *buffer, long length)
|
|
{
|
|
long pos; // Current position in the IFF file.
|
|
long oldpos; // Record of start of chunk offset.
|
|
long endpos; // end of file offset before we write our data
|
|
long value;
|
|
BOOL odd; // Is length odd?
|
|
char pad = 0; // Optional padding byte for even sized chunks.
|
|
|
|
/*
|
|
** Get the current end of file (before we write more data to the file)
|
|
*/
|
|
pos = Seek_File (file, 0L, SEEK_CUR);
|
|
endpos = Seek_File (file, 0L, SEEK_END);
|
|
Seek_File (file, pos, SEEK_SET);
|
|
|
|
if (length) {
|
|
value = id;
|
|
odd = (short)length & 0x01;
|
|
|
|
Write_File(file, &value, 4L);
|
|
oldpos = Seek_File(file, 0L, SEEK_CUR);
|
|
Write_File(file, &value, 4L);
|
|
Write_File(file, buffer, length);
|
|
pos = Seek_File(file, 0L, SEEK_CUR);
|
|
if (odd) {
|
|
Write_File(file, &pad, 1L);
|
|
}
|
|
|
|
/*
|
|
** Update the chunk size long.
|
|
*/
|
|
Seek_File(file, oldpos, SEEK_SET);
|
|
value = IFFize_LONG((pos - oldpos)-4);
|
|
Write_File(file, &value, 4L);
|
|
|
|
/*
|
|
** Update the file size LONG. if we are not just overwriting existing data
|
|
*/
|
|
// (MCC)
|
|
if ( endpos < pos ) {
|
|
Seek_File(file, 4L, SEEK_SET);
|
|
value = IFFize_LONG((pos+odd) - 8);
|
|
Write_File(file, &value, 4L);
|
|
}
|
|
|
|
/*
|
|
** Return to end of file.
|
|
*/
|
|
Seek_File(file, 0L, SEEK_END);
|
|
}
|
|
}
|
|
|
|
|