| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699 |
- /*
- ** Command & Conquer Red Alert(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** 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 3 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, see <http://www.gnu.org/licenses/>.
- */
- /****************************************************************************
- *
- * C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
- *
- *----------------------------------------------------------------------------
- *
- * FILE
- * iff.c
- *
- * DESCRIPTION
- * IFF manager. (32-Bit protected mode)
- *
- * PROGRAMMER
- * Denzil E. Long, Jr.
- *
- * DATE
- * January 26, 1995
- *
- *----------------------------------------------------------------------------
- *
- * PUBLIC
- * OpenIFF - Open an IFF for reading or writting.
- * CloseIFF - Close an IFF.
- * ReadForm - Read the IFF FORM, size and type of the file.
- * WriteForm - Write IFF form ID, size and type fields.
- * ReadChunkHeader - Read the IFF chunk identification header.
- * WriteChunkHeader - Write an IFF chunk identification header.
- * WriteChunk - Write an IFF chunk with data from a buffer.
- * WriteChunkBytes - Write data from a buffer to the IFF stream.
- * SkipChunkBytes - Skip bytes in a chunk.
- * FindChunk - Scan for a specific chunk name.
- * IDtoStr - Convert a longword identifier to a NULL-terminated
- * string.
- * CurrentFilePos - Get the current file position.
- *
- ****************************************************************************/
- #include <stdio.h>
- #include <malloc.h>
- #include <io.h>
- #include <fcntl.h>
- #include <sys\stat.h>
- #include <mem.h>
- #include "iff.h"
- /****************************************************************************
- *
- * NAME
- * OpenIFF - Open an IFF for reading or writting.
- *
- * SYNOPSIS
- * IFFHandle = OpenIFF(Name, Mode)
- *
- * IFFHandle *OpenIFF(char *, long);
- *
- * FUNCTION
- * Opens an IFF for a new read or write. The direction of the I/O is
- * given by the value of Mode, which can be either IFF_READ or IFF_WRITE.
- *
- * INPUTS
- * Name - Pointer to name of file to open.
- * Mode - IFF_READ or IFF_WRITE.
- *
- * RESULT
- * IFFHandle - Pointer to IFFHandle structure or NULL if error.
- *
- ****************************************************************************/
- IFFHandle *OpenIFF(char *name, long mode)
- {
- IFFHandle *iff;
- /* Allocate IFFHandle structure. */
- if ((iff = (IFFHandle *)malloc(sizeof(IFFHandle))) != NULL) {
- /* Initialize handle.*/
- memset(iff, 0, sizeof(IFFHandle));
- iff->flags = mode;
- switch (mode) {
- case IFFF_READ:
- iff->fh = open(name, O_RDONLY|O_BINARY);
- break;
- case IFFF_WRITE:
- iff->fh = open(name, (O_CREAT|O_TRUNC|O_WRONLY|O_BINARY),
- (S_IREAD|S_IWRITE));
- printf("\r");
- break;
- case (IFFF_READ|IFFF_WRITE):
- iff->fh = open(name, (O_RDWR|O_BINARY), (S_IREAD|S_IWRITE));
- break;
- default:
- iff->fh = -1;
- break;
- }
- /* If something went wrong we must free up any resources
- * that we have opened.
- */
- if (iff->fh == -1) {
- free(iff);
- iff = NULL;
- }
- }
- return (iff);
- }
- /****************************************************************************
- *
- * NAME
- * CloseIFF - Close an IFF.
- *
- * SYNOPSIS
- * CloseIFF(IFFHandle)
- *
- * void CloseIFF(IFFHandle *);
- *
- * FUNCTION
- * Completes an IFF read or write operation.
- *
- * INPUTS
- * IFFHandle - Pointer to IFFHandle structure.
- *
- * RESULT
- * NONE
- *
- ****************************************************************************/
- void CloseIFF(IFFHandle *iff)
- {
- long length;
- /* Write the length of the FORM */
- if ((iff->flags & IFFF_WRITE) && ((iff->form.size == 0)
- || (iff->scan > iff->form.size))) {
- lseek(iff->fh, 4, SEEK_SET);
- length = REVERSE_LONG(iff->scan);
- write(iff->fh, &length, 4);
- }
- close(iff->fh);
- free(iff);
- }
- /****************************************************************************
- *
- * NAME
- * ReadForm - Read the IFF FORM, size and type of the file.
- *
- * SYNOPSIS
- * Error = ReadForm(IFFHandle, FormHeader)
- *
- * long ReadForm(IFFHandle *, FormHeader *);
- *
- * FUNCTION
- * Read in the IFF form, size, type information. If the FormHeader
- * structure pointer is NULL then the FORM will be read into the
- * IFFHandles form structure.
- *
- * INPUTS
- * IFFHandle - Pointer to IFFHandle structure.
- * FormHeader - Pointer to FormHeader structure.
- *
- * RESULT
- * Error - 0 if successful or IFFERR_??? error code.
- *
- ****************************************************************************/
- long ReadForm(IFFHandle *iff, FormHeader *form)
- {
- FormHeader *ptr;
- long error;
- /* Read the FORM into the IFFHandle or the provided FormHeader. */
- if (form == NULL) {
- ptr = &iff->form;
- } else {
- ptr = form;
- }
- /* Read in IFF FORM from the file stream.. */
- if ((error = read(iff->fh, ptr, 12)) == 12) {
- ptr->size = REVERSE_LONG(ptr->size);
- iff->scan = 4;
- error = 0;
- } else {
- if (error == -1)
- error = IFFERR_READ;
- else if (error == 0)
- error = IFFERR_EOF;
- }
- return (error);
- }
- /****************************************************************************
- *
- * NAME
- * WriteForm - Write IFF form ID, size and type fields.
- *
- * SYNOPSIS
- * Error = WriteForm(IFFHandle)
- *
- * long WriteForm(IFFHandle, FormHeader *);
- *
- * FUNCTION
- * Write out the IFF form, size, type information. If the size field
- * is zero then the IFF form size will be calculated and written by
- * the CloseIFF() function. If the FormHeader structure pointer is NULL
- * the the form from the IFFHandle will be written.
- *
- * INPUTS
- * IFFHandle - Pointer to IFFHandle structure.
- * FormHeader - Pointer to FormHeader structure.
- *
- * RESULT
- * Error - 0 if successful or IFFERR_??? error code.
- *
- ****************************************************************************/
- long WriteForm(IFFHandle *iff, FormHeader *form)
- {
- FormHeader *ptr;
- long error = 0;
- /* Use the FORM from the IFFHandle or the provided FormHeader. */
- if (form == NULL) {
- ptr = &iff->form;
- } else {
- ptr = form;
- }
- /* Write the IFF form to the file stream. */
- if (iff->flags & IFFF_WRITE) {
- ptr->size = REVERSE_LONG(ptr->size);
- if (write(iff->fh, ptr, 12) == 12) {
- iff->scan = 4;
- } else {
- error = IFFERR_WRITE;
- }
- } else {
- error = IFFERR_WRITE;
- }
- return (error);
- }
- /****************************************************************************
- *
- * NAME
- * ReadChunkHeader - Read the IFF chunk identification header.
- *
- * SYNOPSIS
- * Error = ReadChunkHeader(IFFHandle)
- *
- * long ReadChunkHeader(IFFHandle *);
- *
- * FUNCTION
- * Read the IFF identification header from the files data stream.
- *
- * INPUTS
- * IFFHandle - Pointer to IFFHandle structure.
- *
- * RESULT
- * Error - 0 if successful or IFFERR_??? error code.
- *
- ****************************************************************************/
- long ReadChunkHeader(IFFHandle *iff)
- {
- long error = 0;
- /* Skip any part of the previous chunk that hasn't been processed. */
- if ((iff->cn.size != 0) && (iff->cn.scan < PADSIZE(iff->cn.size))) {
- error = lseek(iff->fh, (PADSIZE(iff->cn.size) - iff->cn.scan), SEEK_CUR);
- if (error == -1) {
- error = IFFERR_READ;
- } else {
- error = 0;
- }
- }
- /* Read in the next chunk header context. */
- if (!error) {
- if ((error = read(iff->fh, &iff->cn, 8)) == 8) {
- error = 0;
- iff->scan += 8;
- iff->cn.size = REVERSE_LONG(iff->cn.size);
- iff->cn.scan = 0;
- } else {
- if (error == -1) {
- error = IFFERR_READ;
- } else if (error == 0) {
- error = IFFERR_EOF;
- }
- }
- }
- return (error);
- }
- /****************************************************************************
- *
- * NAME
- * WriteChunkHeader - Write an IFF chunk identification header.
- *
- * SYNOPSIS
- * Error = WriteChunkHeader(IFFHandle, ID, Size)
- *
- * long WriteChunkHeader(IFFHandle *, long, long);
- *
- * FUNCTION
- * Write an IFF identification header to the files data stream.
- *
- * INPUTS
- * IFFHandle - Pointer to IFFHandle structure.
- * ID - ID code of chunk.
- * Size - Size of chunk in bytes (WORD aligned).
- *
- * RESULT
- * Error - 0 if successful or IFFERR_??? error code.
- *
- ****************************************************************************/
- long WriteChunkHeader(IFFHandle *iff, long id, long size)
- {
- long error = 0;
- /* Make sure it is okay to write. */
- if (iff->flags & IFFF_WRITE) {
- iff->cn.id = id;
- iff->cn.size = REVERSE_LONG(size);
- iff->cn.scan = 0;
- if (write(iff->fh, &iff->cn, 8) == 8) {
- iff->scan += 8;
- } else {
- error = IFFERR_WRITE;
- }
- }
- return (error);
- }
- /****************************************************************************
- *
- * NAME
- * WriteChunk - Write an IFF chunk with data from a buffer.
- *
- * SYNOPSIS
- * Actual = WriteChunk(IFFHandle, ID, Buffer, Size)
- *
- * long WriteChunk(IFFHandle *, long, char *, long);
- *
- * FUNCTION
- * Write a IFF chunk at the current file position.
- *
- * INPUTS
- * IFFHandle - Pointer to IFFHandle structure.
- * ID - ID code of chunk.
- * Buffer - Pointer to buffer area with bytes to be written.
- * Size - Number of bytes to write.
- *
- * RESULT
- * Actual - (positive) Bytes written or (negative) IFFERR_??? error code.
- *
- ****************************************************************************/
- long WriteChunk(IFFHandle *iff, long id, char *buffer, long size)
- {
- Context cn;
- long actual;
- /* Make sure we can write to this file. */
- if (iff->flags & IFFF_WRITE) {
- cn.id = id;
- cn.size = REVERSE_LONG(size);
- /* Write chunk header. */
- if (write(iff->fh, &cn, 8) == 8) {
- iff->scan += 8;
- iff->cn.scan += 8;
- /* Write chunk data. */
- actual = write(iff->fh, buffer, size);
- if (actual == size) {
- iff->scan += actual;
- iff->cn.scan += actual;
- /* Write chunk padding if necessary. */
- if (PADSIZE(size) > size) {
- id = 0;
- if (write(iff->fh, &id, 1) == 1) {
- iff->scan++;
- iff->cn.scan++;
- } else {
- actual = IFFERR_WRITE;
- }
- }
- } else {
- actual = IFFERR_WRITE;
- }
- } else {
- actual = IFFERR_WRITE;
- }
- } else {
- actual = IFFERR_WRITE;
- }
- return (actual);
- }
- /****************************************************************************
- *
- * NAME
- * WriteChunkBytes - Write data from a buffer to the IFF stream.
- *
- * SYNOPSIS
- * Actual = WriteChunkBytes(IFFHandle, Buffer, Size)
- *
- * long WriteChunk(IFFHandle *, char *, long);
- *
- * FUNCTION
- * Write a IFF chunk at the current file position.
- *
- * INPUTS
- * IFFHandle - Pointer to IFFHandle structure.
- * Buffer - Pointer to buffer area with bytes to be written.
- * Size - Number of bytes to write.
- *
- * RESULT
- * Actual - (positive) Bytes written or (negative) IFFERR_??? error code.
- *
- ****************************************************************************/
- long WriteChunkBytes(IFFHandle *iff, char *buffer, long size)
- {
- long actual;
- /* Make sure we can write to this file. */
- if (iff->flags & IFFF_WRITE) {
- /* Write data. */
- if ((actual = (unsigned short)write(iff->fh, buffer, size)) == size) {
- iff->scan += actual;
- iff->cn.scan += actual;
- } else {
- actual = IFFERR_WRITE;
- }
- } else {
- actual = IFFERR_WRITE;
- }
- return (actual);
- }
- /****************************************************************************
- *
- * NAME
- * ReadChunkBytes - Read data from a chunk into a buffer.
- *
- * SYNOPSIS
- * Actual = ReadChunkBytes(IFFHandle, Buffer, Length)
- *
- * long ReadChunkBytes(IFFHandle *, char *, long);
- *
- * FUNCTION
- * Read in 'Length' number of bytes from the current chunk context.
- * If the specified length exceeds the number of bytes remaining in the
- * chunk ReadChunkBytes() will read in only the number of remaining
- * bytes. ReadChunkBytes() will never read beyond the scope of the
- * current chunk.
- *
- * INPUTS
- * IFFHandle - Pointer to IFFHandle structure.
- * Buffer - Pointer to buffer to read data into.
- * Length - Number of bytes to read.
- *
- * RESULT
- * Actual - (positive) Bytes written or (negative) IFFERR_??? error code.
- *
- ****************************************************************************/
- long ReadChunkBytes(IFFHandle *iff, char *buffer, long size)
- {
- long actual;
- /* If the actual bytes remaining in the current chunk is less than
- * the requested bytes to read then adjust the read request size
- * to only read in the bytes that remain in the chunk.
- */
- actual = (iff->cn.size - iff->cn.scan);
- if (size > actual) {
- size = actual;
- }
- /* Read in the requested number of bytes. */
- if ((actual = read(iff->fh, buffer, size)) != size) {
- actual = IFFERR_READ;
- } else {
- iff->scan += actual;
- iff->cn.scan += actual;
- }
- return (actual);
- }
- /****************************************************************************
- *
- * NAME
- * SkipChunkBytes - Skip bytes in a chunk.
- *
- * SYNOPSIS
- * Error = SkipChunkBytes(IFFHandle, Skip)
- *
- * long SkipChunkBytes(IFFHandle *, long);
- *
- * FUNCTION
- * Skip the specified number of bytes of the chunk.
- *
- * INPUTS
- * IFFHandle - Pointer to IFFHandle structure.
- * Skip - Number of bytes to skip.
- *
- * RESULT
- * Error - 0 if successful or FAIL_??? error code.
- *
- ****************************************************************************/
- long SkipChunkBytes(IFFHandle *iff, long skip)
- {
- long error = 0;
- if (lseek(iff->fh, skip, SEEK_CUR) == -1) {
- error = IFFERR_READ;
- } else {
- iff->scan += skip;
- iff->cn.scan += skip;
- }
- return (error);
- }
- /****************************************************************************
- *
- * NAME
- * FindChunk - Scan for a specific chunk name.
- *
- * SYNOPSIS
- * Error = FindChunk(IFFHandle, ID)
- *
- * long FindChunk(IFFHandle *, long);
- *
- * FUNCTION
- * Scan from the current file position for the next occurance of the
- * specified chunk ID. When a match is found the function will return
- * with the matching chunk as the current context.
- *
- * INPUTS
- * IFFHandle - Pointer to IFFHandle structure.
- * ID - ID code of chunk.
- *
- * RESULT
- * Error - 0 if successful or FAIL_??? error code.
- *
- ****************************************************************************/
- long FindChunk(IFFHandle *iff, long id)
- {
- long found = 0;
- long error = 0;
- /* Invalid handle check. */
- if (iff != NULL) {
- /* Scan until we have a match or an error. */
- while ((found == 0) && !(error = ReadChunkHeader(iff))) {
- /* If we found a match the terminate scan, otherwise skip this
- * chunk and process the next.
- */
- if (iff->cn.id == id) {
- found = 1;
- } else {
- error = SkipChunkBytes(iff, PADSIZE(iff->cn.size));
- }
- }
- }
- return (error);
- }
- /****************************************************************************
- *
- * NAME
- * IDtoStr - Convert a longword identifier to a NULL-terminated string.
- *
- * SYNOPSIS
- * String = IDtoStr(ID, Buffer)
- *
- * char *IDtoStr(long, char *);
- *
- * FUNCTION
- * Writes the ASCII equivalent of the given longword ID into buffer as a
- * NULL-terminated string.
- *
- * INPUTS
- * ID - Longword ID.
- * Buffer - Character buffer to accept string (at least 5 characters).
- *
- * RESULT
- * String - The value of "Buffer".
- *
- ****************************************************************************/
- char *IDtoStr(long id, char *buf)
- {
- memcpy(buf, &id, 4);
- *(buf + 4) = 0;
- return (buf);
- }
- /****************************************************************************
- *
- * NAME
- * CurrentFilePos - Get the current file position.
- *
- * SYNOPSIS
- * Position = CurrentFilePos(IFFHandle)
- *
- * long CurrentFilePos(IFFHandle *);
- *
- * FUNCTION
- * This function returns the offset in bytes of the current file position
- * from the beginning of the IFF.
- *
- * INPUTS
- * IFFHandle - Pointer to IFFHandle structure.
- *
- * RESULT
- * Position - Offset in bytes from the beginning of the file to the
- * current position.
- *
- ****************************************************************************/
- long CurrentFilePos(IFFHandle *iff)
- {
- long offset;
- if ((offset = lseek(iff->fh, 0, SEEK_CUR)) == -1) {
- offset = IFFERR_READ;
- }
- return (offset);
- }
|