IFF.CPP (13976B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 16 /*************************************************************************** 17 ** 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 ** 18 *************************************************************************** 19 * * 20 * Project Name : Westwood Library * 21 * * 22 * File Name : IFF.C * 23 * * 24 * Programmer : Joe L. Bostic * 25 * * 26 * Start Date : May 16, 1991 * 27 * * 28 * Last Update : April 19, 1994 [SKB] * 29 * * 30 * * 31 * IFF reader code designed for loading pictures (ILBM or PBM). * 32 * * 33 *-------------------------------------------------------------------------* 34 * Functions: * 35 * Close_Iff_File -- Closes an IFF file handle. * 36 * Get_Iff_Chunk_Size -- Get the size of the given IFF chunk. * 37 * Open_Iff_File -- Opens an IFF file for reading. * 38 * Read_Iff_Chunk -- Reads a chunk from an IFF file. * 39 * Write_Iff_Chunk -- Writes an IFF chuck out. * 40 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 41 42 #include "iff.h" 43 #include "file.h" 44 45 #define ID_FORM MAKE_ID('F','O','R','M') 46 47 #ifdef MIN 48 #undef MIN 49 #endif 50 51 /*************************************************************************** 52 * OPEN_IFF_FILE -- Opens an IFF file for reading. * 53 * * 54 * This function will open an IFF file for reading. It will perform * 55 * a the simple validity test of checking the first four bytes to make * 56 * sure they are "FORM". The value returned is the filehandle of the * 57 * opened file. * 58 * * 59 * INPUT: filename - ASCII name of the IFF file to be opened. * 60 * * 61 * OUTPUT: Returns the filehandle. If there is an error or the file * 62 * is not an IFF FORM then -1 will be returned. * 63 * * 64 * WARNINGS: You are responsible for error handling if this function * 65 * returns -1 (not an IFF file). * 66 * * 67 * HISTORY: * 68 * 05/16/1991 JLB : Created. * 69 * 04/19/1994 SKB : Update to 32 bit library. * 70 *=========================================================================*/ 71 int __cdecl Open_Iff_File(char const *filename) 72 { 73 int fh; // File handle. 74 long type; // IFF file type. 75 76 77 /* We want to be able to open the file for READ | WRITE, but we do not 78 want the Open_File to create it. So check to see if it exists before 79 the Open_File */ 80 81 // fh = Open_File(filename, READ); // Open the source file for READ 82 // Close_File(fh); 83 84 //fh = Open_File(filename, READ | WRITE); // Open the source file again 85 fh = Open_File(filename, READ); // Open the source file again 86 87 // Validate that it is a FORM type. 88 89 Read_File(fh, &type, 4L); 90 91 if (type == ID_FORM) { 92 93 // The file is valid (so far). Position the read so that the actual 94 // IFF file type code can be read. 95 96 Seek_File(fh, 4L, SEEK_CUR); // Skip the filesize bytes. 97 98 } else { 99 100 // This is NOT an IFF file. Close the source file and return with 101 // the error code. 102 Close_File(fh); 103 fh = WW_ERROR; 104 } 105 return fh; 106 } 107 108 109 /*************************************************************************** 110 * CLOSE_IFF_FILE -- Closes an IFF file handle. * 111 * * 112 * The routine will close the file that was opened with the * 113 * Open_Iff_File() function. * 114 * * 115 * INPUT: fh - File handle that was returned from Open_Iff_File(). * 116 * * 117 * OUTPUT: none * 118 * * 119 * WARNINGS: none * 120 * * 121 * HISTORY: * 122 * 05/16/1991 JLB : Created. * 123 * 04/19/1994 SKB : Update to 32 bit library. * 124 *=========================================================================*/ 125 void __cdecl Close_Iff_File(int fh) 126 { 127 if (fh != WW_ERROR) Close_File(fh); 128 } 129 130 131 /*************************************************************************** 132 * GET_IFF_CHUNK_SIZE -- Get the size of the given IFF chunk. * 133 * * 134 * INPUT: int file handle to open IFF file, long id to get size of * 135 * * 136 * OUTPUT: long size of the chunk or 0L if it was not found * 137 * * 138 * WARNINGS: none * 139 * * 140 * HISTORY: * 141 * 06/03/1991 CY : Created. * 142 * 04/19/1994 SKB : Update to 32 bit library. * 143 *=========================================================================*/ 144 unsigned long __cdecl Get_Iff_Chunk_Size(int fh, long id) 145 { 146 long form; // Chunk iff form name. 147 long chunksize; // Size of the chunk. 148 char first_iteration; // Check once the current chunk name 149 150 151 first_iteration = TRUE; 152 153 for (;;) { 154 if (Read_File(fh, &form, 4L) != 4L && !first_iteration) break; 155 156 157 if (Read_File(fh, (char *) &chunksize, 4L) != 4L && !first_iteration) break; 158 159 #if(IBM) 160 chunksize = Reverse_Long(chunksize); 161 #endif 162 163 if (id == form) { 164 Seek_File(fh, -8L, SEEK_CUR); // Seek back to the start of 165 return(chunksize); // the chunk & return size 166 } else { 167 168 if (first_iteration) { 169 Seek_File(fh, 12L, SEEK_SET); // Start at beginning of file. 170 first_iteration = FALSE; // Don't do this again 171 } else { 172 173 /* Otherwise, go to the next chunk in the file */ 174 175 chunksize = (chunksize + 1) & 0xFFFFFFFEL; 176 Seek_File(fh, chunksize, SEEK_CUR); 177 } 178 } 179 } 180 181 return(0L); 182 } 183 184 185 /*************************************************************************** 186 * READ_IFF_CHUNK -- Reads a chunk from an IFF file. * 187 * * 188 * Once an IFF file is opened, various chunks must be read from it. * 189 * This routine will search through the IFF file and load in the * 190 * specified chunk. It will scan through the entire file when * 191 * searching for the chunk. It will load the FIRST chunk of the given * 192 * type. * 193 * * 194 * INPUT: fh - File handle of IFF file. * 195 * * 196 * id - Chunk ID code. * 197 * * 198 * buffer - Pointer to buffer to load the chunk. * 199 * * 200 * maxsize - Maximum data bytes to read. * 201 * * 202 * OUTPUT: Returns with the number of bytes read from the chunk. * 203 * If 0 is returned, this indicates that the chunk wasn't * 204 * found. * 205 * * 206 * WARNINGS: none * 207 * * 208 * HISTORY: * 209 * 05/16/1991 JLB : Created. * 210 * 04/19/1994 SKB : Update to 32 bit library. * 211 *=========================================================================*/ 212 unsigned long __cdecl Read_Iff_Chunk(int fh, long id, void *buffer, unsigned long maxsize) 213 { 214 long form; // Chunk iff form name. 215 unsigned long chunksize; // Size of the chunk. 216 char first_iteration; // Check once the current chunk name 217 218 first_iteration = TRUE; 219 220 for (;;) { 221 if (Read_File(fh, &form, 4L) != 4L && !first_iteration) break; 222 223 if (Read_File(fh, (char *) &chunksize, 4L) != 4L && !first_iteration) break; 224 225 #if(IBM) 226 chunksize = Reverse_Long(chunksize); 227 #endif 228 229 if (id == form) { 230 231 maxsize = MIN(maxsize, chunksize); 232 Read_File(fh, buffer, maxsize); // Read the buffer. 233 234 chunksize = (chunksize + 1) & 0xFFFFFFFEL; 235 if (maxsize < chunksize) { 236 Seek_File(fh, chunksize - maxsize, SEEK_CUR); 237 } 238 return(maxsize); 239 } else { 240 241 if (first_iteration) { 242 Seek_File(fh, 12L, SEEK_SET); // Start at beginning of file. 243 first_iteration = FALSE; // Don't do this again 244 245 } else { 246 247 /* Otherwise, go to the next chunk in the file */ 248 249 chunksize = (chunksize + 1) & 0xFFFFFFFEL; 250 Seek_File(fh, chunksize, SEEK_CUR); 251 } 252 } 253 } 254 255 return(0L); 256 } 257 258 259 260 /*************************************************************************** 261 * WRITE_IFF_CHUNK -- Writes an IFF chuck out. * 262 * * 263 * INPUT: * 264 * * 265 * OUTPUT: * 266 * * 267 * WARNINGS: * 268 * * 269 * HISTORY: * 270 * 04/19/1994 SKB : Created. * 271 *=========================================================================*/ 272 void __cdecl Write_Iff_Chunk(int file, long id, void *buffer, long length) 273 { 274 long pos; // Current position in the IFF file. 275 long oldpos; // Record of start of chunk offset. 276 long endpos; // end of file offset before we write our data 277 long value; 278 BOOL odd; // Is length odd? 279 char pad = 0; // Optional padding byte for even sized chunks. 280 281 /* 282 ** Get the current end of file (before we write more data to the file) 283 */ 284 pos = Seek_File (file, 0L, SEEK_CUR); 285 endpos = Seek_File (file, 0L, SEEK_END); 286 Seek_File (file, pos, SEEK_SET); 287 288 if (length) { 289 value = id; 290 odd = (short)length & 0x01; 291 292 Write_File(file, &value, 4L); 293 oldpos = Seek_File(file, 0L, SEEK_CUR); 294 Write_File(file, &value, 4L); 295 Write_File(file, buffer, length); 296 pos = Seek_File(file, 0L, SEEK_CUR); 297 if (odd) { 298 Write_File(file, &pad, 1L); 299 } 300 301 /* 302 ** Update the chunk size long. 303 */ 304 Seek_File(file, oldpos, SEEK_SET); 305 value = IFFize_LONG((pos - oldpos)-4); 306 Write_File(file, &value, 4L); 307 308 /* 309 ** Update the file size LONG. if we are not just overwriting existing data 310 */ 311 // (MCC) 312 if ( endpos < pos ) { 313 Seek_File(file, 4L, SEEK_SET); 314 value = IFFize_LONG((pos+odd) - 8); 315 Write_File(file, &value, 4L); 316 } 317 318 /* 319 ** Return to end of file. 320 */ 321 Seek_File(file, 0L, SEEK_END); 322 } 323 } 324 325