1 //-----------------------------------------------------------------------------
2 //
3 // ImageLib Sources
4 // Copyright (C) 2000-2009 by Denton Woods
5 // Last modified: 01/04/2009
6 //
7 // Filename: src-IL/src/il_files.c
8 //
9 // Description: File handling for DevIL
10 //
11 //-----------------------------------------------------------------------------
12 
13 
14 #define __FILES_C
15 #include "il_internal.h"
16 #include <stdarg.h>
17 
18 
19 // All specific to the next set of functions
20 ILboolean	ILAPIENTRY iEofFile(void);
21 ILboolean	ILAPIENTRY iEofLump(void);
22 ILint		ILAPIENTRY iGetcFile(void);
23 ILint		ILAPIENTRY iGetcLump(void);
24 ILuint		ILAPIENTRY iReadFile(void *Buffer, ILuint Size, ILuint Number);
25 ILuint		ILAPIENTRY iReadLump(void *Buffer, const ILuint Size, const ILuint Number);
26 ILint		ILAPIENTRY iSeekRFile(ILint Offset, ILuint Mode);
27 ILint		ILAPIENTRY iSeekRLump(ILint Offset, ILuint Mode);
28 ILint		ILAPIENTRY iSeekWFile(ILint Offset, ILuint Mode);
29 ILint		ILAPIENTRY iSeekWLump(ILint Offset, ILuint Mode);
30 ILuint		ILAPIENTRY iTellRFile(void);
31 ILuint		ILAPIENTRY iTellRLump(void);
32 ILuint		ILAPIENTRY iTellWFile(void);
33 ILuint		ILAPIENTRY iTellWLump(void);
34 ILint		ILAPIENTRY iPutcFile(ILubyte Char);
35 ILint		ILAPIENTRY iPutcLump(ILubyte Char);
36 ILint		ILAPIENTRY iWriteFile(const void *Buffer, ILuint Size, ILuint Number);
37 ILint		ILAPIENTRY iWriteLump(const void *Buffer, ILuint Size, ILuint Number);
38 ILHANDLE	FileRead = NULL, FileWrite = NULL;
39 const void *ReadLump = NULL;
40 void 		*WriteLump = NULL;
41 ILuint		ReadLumpPos = 0, ReadLumpSize = 0, ReadFileStart = 0, WriteFileStart = 0;
42 ILuint		WriteLumpPos = 0, WriteLumpSize = 0;
43 
44 fGetcProc	GetcProcCopy;
45 fReadProc	ReadProcCopy;
46 fSeekRProc	SeekProcCopy;
47 fTellRProc	TellProcCopy;
48 ILHANDLE	(ILAPIENTRY *iopenCopy)(ILconst_string);
49 void		(ILAPIENTRY *icloseCopy)(ILHANDLE);
50 
51 fPutcProc	PutcProcCopy;
52 fSeekWProc	SeekWProcCopy;
53 fTellWProc	TellWProcCopy;
54 fWriteProc	WriteProcCopy;
55 ILHANDLE	(ILAPIENTRY *iopenwCopy)(ILconst_string);
56 void		(ILAPIENTRY *iclosewCopy)(ILHANDLE);
57 
58 ILboolean	UseCache = IL_FALSE;
59 ILubyte		*Cache = NULL;
60 ILuint		CacheSize, CachePos, CacheStartPos, CacheBytesRead;
61 
62 // "Fake" size functions
63 //  Definitions are in il_size.c.
64 ILint		ILAPIENTRY iSizeSeek(ILint Offset, ILuint Mode);
65 ILuint		ILAPIENTRY iSizeTell(void);
66 ILint		ILAPIENTRY iSizePutc(ILubyte Char);
67 ILint		ILAPIENTRY iSizeWrite(const void *Buffer, ILuint Size, ILuint Number);
68 
69 // Just preserves the current read functions and replaces
70 //	the current read functions with the default read funcs.
iPreserveReadFuncs()71 void ILAPIENTRY iPreserveReadFuncs()
72 {
73 	// Create backups
74 	GetcProcCopy = GetcProc;
75 	ReadProcCopy = ReadProc;
76 	SeekProcCopy = SeekRProc;
77 	TellProcCopy = TellRProc;
78 	iopenCopy = iopenr;
79 	icloseCopy = icloser;
80 
81 	// Set the standard procs to read
82 	ilResetRead();
83 
84 	return;
85 }
86 
87 
88 // Restores the read functions - must be used after iPreserveReadFuncs().
iRestoreReadFuncs()89 void ILAPIENTRY iRestoreReadFuncs()
90 {
91 	GetcProc = GetcProcCopy;
92 	ReadProc = ReadProcCopy;
93 	SeekRProc = SeekProcCopy;
94 	TellRProc = TellProcCopy;
95 	iopenr = iopenCopy;
96 	icloser = icloseCopy;
97 
98 	return;
99 }
100 
101 
102 // Just preserves the current read functions and replaces
103 //	the current read functions with the default read funcs.
iPreserveWriteFuncs()104 void ILAPIENTRY iPreserveWriteFuncs()
105 {
106 	// Create backups
107 	PutcProcCopy = PutcProc;
108 	SeekWProcCopy = SeekWProc;
109 	TellWProcCopy = TellWProc;
110 	WriteProcCopy = WriteProc;
111 	iopenwCopy = iopenw;
112 	iclosewCopy = iclosew;
113 
114 	// Set the standard procs to write
115 	ilResetWrite();
116 
117 	return;
118 }
119 
120 
121 // Restores the read functions - must be used after iPreserveReadFuncs().
iRestoreWriteFuncs()122 void ILAPIENTRY iRestoreWriteFuncs()
123 {
124 	PutcProc = PutcProcCopy;
125 	SeekWProc = SeekWProcCopy;
126 	TellWProc = TellWProcCopy;
127 	WriteProc = WriteProcCopy;
128 	iopenw = iopenwCopy;
129 	iclosew = iclosewCopy;
130 
131 	return;
132 }
133 
134 
135 // Next 7 functions are the default read functions
136 
iDefaultOpenR(ILconst_string FileName)137 ILHANDLE ILAPIENTRY iDefaultOpenR(ILconst_string FileName)
138 {
139 #ifndef _UNICODE
140 	return (ILHANDLE)fopen((char*)FileName, "rb");
141 #else
142 	// Windows has a different function, _wfopen, to open UTF16 files,
143 	//  whereas Linux just uses fopen for its UTF8 files.
144 	#ifdef _WIN32
145 		return (ILHANDLE)_wfopen(FileName, L"rb");
146 	#else
147 		return (ILHANDLE)fopen((char*)FileName, "rb");
148 	#endif
149 #endif//UNICODE
150 }
151 
152 
iDefaultCloseR(ILHANDLE Handle)153 void ILAPIENTRY iDefaultCloseR(ILHANDLE Handle)
154 {
155 	fclose((FILE*)Handle);
156 	return;
157 }
158 
159 
iDefaultEof(ILHANDLE Handle)160 ILboolean ILAPIENTRY iDefaultEof(ILHANDLE Handle)
161 {
162 	ILuint OrigPos, FileSize;
163 
164 	// Find out the filesize for checking for the end of file
165 	OrigPos = itell();
166 	iseek(0, IL_SEEK_END);
167 	FileSize = itell();
168 	iseek(OrigPos, IL_SEEK_SET);
169 
170 	if (itell() >= FileSize)
171 		return IL_TRUE;
172 	return IL_FALSE;
173 }
174 
175 
iDefaultGetc(ILHANDLE Handle)176 ILint ILAPIENTRY iDefaultGetc(ILHANDLE Handle)
177 {
178 	ILint Val;
179 
180 	if (!UseCache) {
181 		Val = fgetc((FILE*)Handle);
182 		if (Val == IL_EOF)
183 			ilSetError(IL_FILE_READ_ERROR);
184 	}
185 	else {
186 		Val = 0;
187 		if (iread(&Val, 1, 1) != 1)
188 			return IL_EOF;
189 	}
190 	return Val;
191 }
192 
193 
iDefaultRead(void * Buffer,ILuint Size,ILuint Number,ILHANDLE Handle)194 ILint ILAPIENTRY iDefaultRead(void *Buffer, ILuint Size, ILuint Number, ILHANDLE Handle)
195 {
196 	return (ILint)fread(Buffer, Size, Number, (FILE*)Handle);
197 }
198 
199 
iDefaultRSeek(ILHANDLE Handle,ILint Offset,ILint Mode)200 ILint ILAPIENTRY iDefaultRSeek(ILHANDLE Handle, ILint Offset, ILint Mode)
201 {
202 	return fseek((FILE*)Handle, Offset, Mode);
203 }
204 
205 
iDefaultWSeek(ILHANDLE Handle,ILint Offset,ILint Mode)206 ILint ILAPIENTRY iDefaultWSeek(ILHANDLE Handle, ILint Offset, ILint Mode)
207 {
208 	return fseek((FILE*)Handle, Offset, Mode);
209 }
210 
211 
iDefaultRTell(ILHANDLE Handle)212 ILint ILAPIENTRY iDefaultRTell(ILHANDLE Handle)
213 {
214 	return ftell((FILE*)Handle);
215 }
216 
217 
iDefaultWTell(ILHANDLE Handle)218 ILint ILAPIENTRY iDefaultWTell(ILHANDLE Handle)
219 {
220 	return ftell((FILE*)Handle);
221 }
222 
223 
iDefaultOpenW(ILconst_string FileName)224 ILHANDLE ILAPIENTRY iDefaultOpenW(ILconst_string FileName)
225 {
226 #ifndef _UNICODE
227 	return (ILHANDLE)fopen((char*)FileName, "wb");
228 #else
229 	// Windows has a different function, _wfopen, to open UTF16 files,
230 	//  whereas Linux just uses fopen.
231 	#ifdef _WIN32
232 		return (ILHANDLE)_wfopen(FileName, L"wb");
233 	#else
234 		return (ILHANDLE)fopen((char*)FileName, "wb");
235 	#endif
236 #endif//UNICODE
237 }
238 
239 
iDefaultCloseW(ILHANDLE Handle)240 void ILAPIENTRY iDefaultCloseW(ILHANDLE Handle)
241 {
242 	fclose((FILE*)Handle);
243 	return;
244 }
245 
246 
iDefaultPutc(ILubyte Char,ILHANDLE Handle)247 ILint ILAPIENTRY iDefaultPutc(ILubyte Char, ILHANDLE Handle)
248 {
249 	return fputc(Char, (FILE*)Handle);
250 }
251 
252 
iDefaultWrite(const void * Buffer,ILuint Size,ILuint Number,ILHANDLE Handle)253 ILint ILAPIENTRY iDefaultWrite(const void *Buffer, ILuint Size, ILuint Number, ILHANDLE Handle)
254 {
255 	return (ILint)fwrite(Buffer, Size, Number, (FILE*)Handle);
256 }
257 
258 
ilResetRead()259 void ILAPIENTRY ilResetRead()
260 {
261 	ilSetRead(iDefaultOpenR, iDefaultCloseR, iDefaultEof, iDefaultGetc,
262 				iDefaultRead, iDefaultRSeek, iDefaultRTell);
263 	return;
264 }
265 
266 
ilResetWrite()267 void ILAPIENTRY ilResetWrite()
268 {
269 	ilSetWrite(iDefaultOpenW, iDefaultCloseW, iDefaultPutc,
270 				iDefaultWSeek, iDefaultWTell, iDefaultWrite);
271 	return;
272 }
273 
274 
275 //! Allows you to override the default file-reading functions.
ilSetRead(fOpenRProc Open,fCloseRProc Close,fEofProc Eof,fGetcProc Getc,fReadProc Read,fSeekRProc Seek,fTellRProc Tell)276 void ILAPIENTRY ilSetRead(fOpenRProc Open, fCloseRProc Close, fEofProc Eof, fGetcProc Getc, fReadProc Read, fSeekRProc Seek, fTellRProc Tell)
277 {
278 	iopenr    = Open;
279 	icloser   = Close;
280 	EofProc   = Eof;
281 	GetcProc  = Getc;
282 	ReadProc  = Read;
283 	SeekRProc = Seek;
284 	TellRProc = Tell;
285 
286 	return;
287 }
288 
289 
290 //! Allows you to override the default file-writing functions.
ilSetWrite(fOpenRProc Open,fCloseRProc Close,fPutcProc Putc,fSeekWProc Seek,fTellWProc Tell,fWriteProc Write)291 void ILAPIENTRY ilSetWrite(fOpenRProc Open, fCloseRProc Close, fPutcProc Putc, fSeekWProc Seek, fTellWProc Tell, fWriteProc Write)
292 {
293 	iopenw    = Open;
294 	iclosew   = Close;
295 	PutcProc  = Putc;
296 	WriteProc = Write;
297 	SeekWProc = Seek;
298 	TellWProc = Tell;
299 
300 	return;
301 }
302 
303 
304 // Tells DevIL that we're reading from a file, not a lump
iSetInputFile(ILHANDLE File)305 void iSetInputFile(ILHANDLE File)
306 {
307 	ieof  = iEofFile;
308 	igetc = iGetcFile;
309 	iread = iReadFile;
310 	iseek = iSeekRFile;
311 	itell = iTellRFile;
312 	FileRead = File;
313 	ReadFileStart = itell();
314 }
315 
316 
317 // Tells DevIL that we're reading from a lump, not a file
iSetInputLump(const void * Lump,ILuint Size)318 void iSetInputLump(const void *Lump, ILuint Size)
319 {
320 	ieof  = iEofLump;
321 	igetc = iGetcLump;
322 	iread = iReadLump;
323 	iseek = iSeekRLump;
324 	itell = iTellRLump;
325 	ReadLump = Lump;
326 	ReadLumpPos = 0;
327 	ReadLumpSize = Size;
328 }
329 
330 
331 // Tells DevIL that we're writing to a file, not a lump
iSetOutputFile(ILHANDLE File)332 void iSetOutputFile(ILHANDLE File)
333 {
334 	// Helps with ilGetLumpPos().
335 	WriteLump = NULL;
336 	WriteLumpPos = 0;
337 	WriteLumpSize = 0;
338 
339 	iputc  = iPutcFile;
340 	iseekw = iSeekWFile;
341 	itellw = iTellWFile;
342 	iwrite = iWriteFile;
343 	FileWrite = File;
344 }
345 
346 
347 // This is only called by ilDetermineSize.  Associates iputc, etc. with
348 //  "fake" writing functions in il_size.c.
iSetOutputFake(void)349 void iSetOutputFake(void)
350 {
351 	iputc  = iSizePutc;
352 	iseekw = iSizeSeek;
353 	itellw = iSizeTell;
354 	iwrite = iSizeWrite;
355 	return;
356 }
357 
358 
359 // Tells DevIL that we're writing to a lump, not a file
iSetOutputLump(void * Lump,ILuint Size)360 void iSetOutputLump(void *Lump, ILuint Size)
361 {
362 	// In this case, ilDetermineSize is currently trying to determine the
363 	//  output buffer size.  It already has the write functions it needs.
364 	if (Lump == NULL)
365 		return;
366 
367 	iputc  = iPutcLump;
368 	iseekw = iSeekWLump;
369 	itellw = iTellWLump;
370 	iwrite = iWriteLump;
371 	WriteLump = Lump;
372 	WriteLumpPos = 0;
373 	WriteLumpSize = Size;
374 }
375 
376 
ilGetLumpPos()377 ILuint ILAPIENTRY ilGetLumpPos()
378 {
379 	if (WriteLump)
380 		return WriteLumpPos;
381 	return 0;
382 }
383 
384 
ilprintf(const char * Line,...)385 ILuint ILAPIENTRY ilprintf(const char *Line, ...)
386 {
387 	char	Buffer[2048];  // Hope this is large enough
388 	va_list	VaLine;
389 	ILuint	i;
390 
391 	va_start(VaLine, Line);
392 	vsprintf(Buffer, Line, VaLine);
393 	va_end(VaLine);
394 
395 	i = ilCharStrLen(Buffer);
396 	iwrite(Buffer, 1, i);
397 
398 	return i;
399 }
400 
401 
402 // To pad zeros where needed...
ipad(ILuint NumZeros)403 void ipad(ILuint NumZeros)
404 {
405 	ILuint i = 0;
406 	for (; i < NumZeros; i++)
407 		iputc(0);
408 	return;
409 }
410 
411 
412 //
413 // The rest of the functions following in this file are quite
414 //	self-explanatory, except where commented.
415 //
416 
417 // Next 12 functions are the default write functions
418 
iEofFile(void)419 ILboolean ILAPIENTRY iEofFile(void)
420 {
421 	return EofProc((FILE*)FileRead);
422 }
423 
424 
iEofLump(void)425 ILboolean ILAPIENTRY iEofLump(void)
426 {
427 	if (ReadLumpSize)
428 		return (ReadLumpPos >= ReadLumpSize);
429 	return IL_FALSE;
430 }
431 
432 
iGetcFile(void)433 ILint ILAPIENTRY iGetcFile(void)
434 {
435 	if (!UseCache) {
436 		return GetcProc(FileRead);
437 	}
438 	if (CachePos >= CacheSize) {
439 		iPreCache(CacheSize);
440 	}
441 
442 	CacheBytesRead++;
443 	return Cache[CachePos++];
444 }
445 
446 
iGetcLump(void)447 ILint ILAPIENTRY iGetcLump(void)
448 {
449 	// If ReadLumpSize is 0, don't even check to see if we've gone past the bounds.
450 	if (ReadLumpSize > 0) {
451 		if (ReadLumpPos + 1 > ReadLumpSize) {
452 			ReadLumpPos--;
453 			ilSetError(IL_FILE_READ_ERROR);
454 			return IL_EOF;
455 		}
456 	}
457 
458 	return *((ILubyte*)ReadLump + ReadLumpPos++);
459 }
460 
461 
iReadFile(void * Buffer,ILuint Size,ILuint Number)462 ILuint ILAPIENTRY iReadFile(void *Buffer, ILuint Size, ILuint Number)
463 {
464 	ILuint	TotalBytes = 0, BytesCopied;
465 	ILuint	BuffSize = Size * Number;
466 	ILuint	NumRead;
467 
468 	if (!UseCache) {
469 		NumRead = ReadProc(Buffer, Size, Number, FileRead);
470 		if (NumRead != Number)
471 			ilSetError(IL_FILE_READ_ERROR);
472 		return NumRead;
473 	}
474 
475 	/*if (Cache == NULL || CacheSize == 0) {  // Shouldn't happen, but we check anyway.
476 		return ReadProc(Buffer, Size, Number, FileRead);
477 	}*/
478 
479 	if (BuffSize < CacheSize - CachePos) {
480 		memcpy(Buffer, Cache + CachePos, BuffSize);
481 		CachePos += BuffSize;
482 		CacheBytesRead += BuffSize;
483 		if (Size != 0)
484 			BuffSize /= Size;
485 		return BuffSize;
486 	}
487 	else {
488 		while (TotalBytes < BuffSize) {
489 			// If loop through more than once, after first, CachePos is 0.
490 			if (TotalBytes + CacheSize - CachePos > BuffSize)
491 				BytesCopied = BuffSize - TotalBytes;
492 			else
493 				BytesCopied = CacheSize - CachePos;
494 
495 			memcpy((ILubyte*)Buffer + TotalBytes, Cache + CachePos, BytesCopied);
496 			TotalBytes += BytesCopied;
497 			CachePos += BytesCopied;
498 			if (TotalBytes < BuffSize) {
499 				iPreCache(CacheSize);
500 			}
501 		}
502 	}
503 
504 	// DW: Changed on 12-27-2008.  Was causing the position to go too far if the
505 	//     cache was smaller than the buffer.
506 	//CacheBytesRead += TotalBytes;
507 	CacheBytesRead = CachePos;
508 	if (Size != 0)
509 		TotalBytes /= Size;
510 	if (TotalBytes != Number)
511 		ilSetError(IL_FILE_READ_ERROR);
512 	return TotalBytes;
513 }
514 
515 
iReadLump(void * Buffer,const ILuint Size,const ILuint Number)516 ILuint ILAPIENTRY iReadLump(void *Buffer, const ILuint Size, const ILuint Number)
517 {
518 	ILuint i, ByteSize = IL_MIN( Size*Number, ReadLumpSize-ReadLumpPos);
519 
520 	for (i = 0; i < ByteSize; i++) {
521 		*((ILubyte*)Buffer + i) = *((ILubyte*)ReadLump + ReadLumpPos + i);
522 		if (ReadLumpSize > 0) {  // ReadLumpSize is too large to care about apparently
523 			if (ReadLumpPos + i > ReadLumpSize) {
524 				ReadLumpPos += i;
525 				if (i != Number)
526 					ilSetError(IL_FILE_READ_ERROR);
527 				return i;
528 			}
529 		}
530 	}
531 
532 	ReadLumpPos += i;
533 	if (Size != 0)
534 		i /= Size;
535 	if (i != Number)
536 		ilSetError(IL_FILE_READ_ERROR);
537 	return i;
538 }
539 
540 
iPreCache(ILuint Size)541 ILboolean iPreCache(ILuint Size)
542 {
543 	// Reading from a memory lump, so don't cache.
544 	if (iread == iReadLump) {
545 		//iUnCache();  // DW: Removed 06-10-2002.
546 		return IL_TRUE;
547 	}
548 
549 	if (Cache) {
550 		ifree(Cache);
551 	}
552 
553 	if (Size == 0) {
554 		Size = 1;
555 	}
556 
557 	Cache = (ILubyte*)ialloc(Size);
558 	if (Cache == NULL) {
559 		return IL_FALSE;
560 	}
561 
562 	UseCache = IL_FALSE;
563 	CacheStartPos = itell();
564 	CacheSize = iread(Cache, 1, Size);
565 	if (CacheSize != Size)
566 		ilGetError();  // Get rid of the IL_FILE_READ_ERROR.
567 
568 	//2003-09-09: uncommented the following line to prevent
569 	//an infinite loop in ilPreCache()
570 	CacheSize = Size;
571 	CachePos = 0;
572 	UseCache = IL_TRUE;
573 	CacheBytesRead = 0;
574 
575 	return IL_TRUE;
576 }
577 
578 
iUnCache()579 void iUnCache()
580 {
581 	//changed 2003-09-01:
582 	//make iUnCache smart enough to return if
583 	//no cache is used
584 	if (!UseCache)
585 		return;
586 
587 	if (iread == iReadLump)
588 		return;
589 
590 	CacheSize = 0;
591 	CachePos = 0;
592 	if (Cache) {
593 		ifree(Cache);
594 		Cache = NULL;
595 	}
596 	UseCache = IL_FALSE;
597 
598 	iseek(CacheStartPos + CacheBytesRead, IL_SEEK_SET);
599 
600 	return;
601 }
602 
603 
iSeekRFile(ILint Offset,ILuint Mode)604 ILint ILAPIENTRY iSeekRFile(ILint Offset, ILuint Mode)
605 {
606 	if (Mode == IL_SEEK_SET)
607 		Offset += ReadFileStart;  // This allows us to use IL_SEEK_SET in the middle of a file.
608 	return SeekRProc(FileRead, Offset, Mode);
609 }
610 
611 
612 // Returns 1 on error, 0 on success
iSeekRLump(ILint Offset,ILuint Mode)613 ILint ILAPIENTRY iSeekRLump(ILint Offset, ILuint Mode)
614 {
615 	switch (Mode)
616 	{
617 		case IL_SEEK_SET:
618 			if (Offset > (ILint)ReadLumpSize)
619 				return 1;
620 			ReadLumpPos = Offset;
621 			break;
622 
623 		case IL_SEEK_CUR:
624 			if (ReadLumpPos + Offset > ReadLumpSize)
625 				return 1;
626 			ReadLumpPos += Offset;
627 			break;
628 
629 		case IL_SEEK_END:
630 			if (Offset > 0)
631 				return 1;
632 			// Should we use >= instead?
633 			if (abs(Offset) > (ILint)ReadLumpSize)  // If ReadLumpSize == 0, too bad
634 				return 1;
635 			ReadLumpPos = ReadLumpSize + Offset;
636 			break;
637 
638 		default:
639 			return 1;
640 	}
641 
642 	return 0;
643 }
644 
645 
iTellRFile(void)646 ILuint ILAPIENTRY iTellRFile(void)
647 {
648 	return TellRProc(FileRead);
649 }
650 
651 
iTellRLump(void)652 ILuint ILAPIENTRY iTellRLump(void)
653 {
654 	return ReadLumpPos;
655 }
656 
657 
iGetFile(void)658 ILHANDLE ILAPIENTRY iGetFile(void)
659 {
660 	return FileRead;
661 }
662 
663 
iGetLump(void)664 const ILubyte* ILAPIENTRY iGetLump(void) {
665 	return (ILubyte*)ReadLump;
666 }
667 
668 
669 
670 // Next 4 functions are the default write functions
671 
iPutcFile(ILubyte Char)672 ILint ILAPIENTRY iPutcFile(ILubyte Char)
673 {
674 	return PutcProc(Char, FileWrite);
675 }
676 
677 
iPutcLump(ILubyte Char)678 ILint ILAPIENTRY iPutcLump(ILubyte Char)
679 {
680 	if (WriteLumpPos >= WriteLumpSize)
681 		return IL_EOF;  // IL_EOF
682 	*((ILubyte*)(WriteLump) + WriteLumpPos++) = Char;
683 	return Char;
684 }
685 
686 
iWriteFile(const void * Buffer,ILuint Size,ILuint Number)687 ILint ILAPIENTRY iWriteFile(const void *Buffer, ILuint Size, ILuint Number)
688 {
689 	ILuint NumWritten;
690 	NumWritten = WriteProc(Buffer, Size, Number, FileWrite);
691 	if (NumWritten != Number) {
692 		ilSetError(IL_FILE_WRITE_ERROR);
693 		return 0;
694 	}
695 	return NumWritten;
696 }
697 
698 
iWriteLump(const void * Buffer,ILuint Size,ILuint Number)699 ILint ILAPIENTRY iWriteLump(const void *Buffer, ILuint Size, ILuint Number)
700 {
701 	ILuint SizeBytes = Size * Number;
702 	ILuint i = 0;
703 
704 	for (; i < SizeBytes; i++) {
705 		if (WriteLumpSize > 0) {
706 			if (WriteLumpPos + i >= WriteLumpSize) {  // Should we use > instead?
707 				ilSetError(IL_FILE_WRITE_ERROR);
708 				WriteLumpPos += i;
709 				return i;
710 			}
711 		}
712 
713 		*((ILubyte*)WriteLump + WriteLumpPos + i) = *((ILubyte*)Buffer + i);
714 	}
715 
716 	WriteLumpPos += SizeBytes;
717 
718 	return SizeBytes;
719 }
720 
721 
iSeekWFile(ILint Offset,ILuint Mode)722 ILint ILAPIENTRY iSeekWFile(ILint Offset, ILuint Mode)
723 {
724 	if (Mode == IL_SEEK_SET)
725 		Offset += WriteFileStart;  // This allows us to use IL_SEEK_SET in the middle of a file.
726 	return SeekWProc(FileWrite, Offset, Mode);
727 }
728 
729 
730 // Returns 1 on error, 0 on success
iSeekWLump(ILint Offset,ILuint Mode)731 ILint ILAPIENTRY iSeekWLump(ILint Offset, ILuint Mode)
732 {
733 	switch (Mode)
734 	{
735 		case IL_SEEK_SET:
736 			if (Offset > (ILint)WriteLumpSize)
737 				return 1;
738 			WriteLumpPos = Offset;
739 			break;
740 
741 		case IL_SEEK_CUR:
742 			if (WriteLumpPos + Offset > WriteLumpSize)
743 				return 1;
744 			WriteLumpPos += Offset;
745 			break;
746 
747 		case IL_SEEK_END:
748 			if (Offset > 0)
749 				return 1;
750 			// Should we use >= instead?
751 			if (abs(Offset) > (ILint)WriteLumpSize)  // If WriteLumpSize == 0, too bad
752 				return 1;
753 			WriteLumpPos = WriteLumpSize + Offset;
754 			break;
755 
756 		default:
757 			return 1;
758 	}
759 
760 	return 0;
761 }
762 
763 
iTellWFile(void)764 ILuint ILAPIENTRY iTellWFile(void)
765 {
766 	return TellWProc(FileWrite);
767 }
768 
769 
iTellWLump(void)770 ILuint ILAPIENTRY iTellWLump(void)
771 {
772 	return WriteLumpPos;
773 }
774