CnC_Remastered_Collection/TIBERIANDAWN/WIN32LIB/IFF.CPP

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);
}
}