1 /*
2 ** files.cpp
3 ** Implements classes for reading from files or memory blocks
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 1998-2008 Randy Heit
7 ** Copyright 2005-2008 Christoph Oelckers
8 ** All rights reserved.
9 **
10 ** Redistribution and use in source and binary forms, with or without
11 ** modification, are permitted provided that the following conditions
12 ** are met:
13 **
14 ** 1. Redistributions of source code must retain the above copyright
15 **    notice, this list of conditions and the following disclaimer.
16 ** 2. Redistributions in binary form must reproduce the above copyright
17 **    notice, this list of conditions and the following disclaimer in the
18 **    documentation and/or other materials provided with the distribution.
19 ** 3. The name of the author may not be used to endorse or promote products
20 **    derived from this software without specific prior written permission.
21 **
22 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 **---------------------------------------------------------------------------
33 **
34 */
35 
36 #ifdef _WIN32
37 #define USE_WINDOWS_DWORD
38 #endif
39 #include "LzmaDec.h"
40 
41 #include "files.h"
42 #include "i_system.h"
43 #include "templates.h"
44 #include "m_misc.h"
45 
46 
47 //==========================================================================
48 //
49 // FileReader
50 //
51 // reads data from an uncompressed file or part of it
52 //
53 //==========================================================================
54 
FileReader()55 FileReader::FileReader ()
56 : File(NULL), Length(0), StartPos(0), FilePos(0), CloseOnDestruct(false)
57 {
58 }
59 
FileReader(const FileReader & other,long length)60 FileReader::FileReader (const FileReader &other, long length)
61 : File(other.File), Length(length), CloseOnDestruct(false)
62 {
63 	FilePos = StartPos = ftell (other.File);
64 }
65 
FileReader(const char * filename)66 FileReader::FileReader (const char *filename)
67 : File(NULL), Length(0), StartPos(0), FilePos(0), CloseOnDestruct(false)
68 {
69 	if (!Open(filename))
70 	{
71 		I_Error ("Could not open %s", filename);
72 	}
73 }
74 
FileReader(FILE * file)75 FileReader::FileReader (FILE *file)
76 : File(file), Length(0), StartPos(0), FilePos(0), CloseOnDestruct(false)
77 {
78 	Length = CalcFileLen();
79 }
80 
FileReader(FILE * file,long length)81 FileReader::FileReader (FILE *file, long length)
82 : File(file), Length(length), CloseOnDestruct(true)
83 {
84 	FilePos = StartPos = ftell (file);
85 }
86 
~FileReader()87 FileReader::~FileReader ()
88 {
89 	if (CloseOnDestruct && File != NULL)
90 	{
91 		fclose (File);
92 		File = NULL;
93 	}
94 }
95 
Open(const char * filename)96 bool FileReader::Open (const char *filename)
97 {
98 	File = fopen (filename, "rb");
99 	if (File == NULL) return false;
100 	FilePos = 0;
101 	StartPos = 0;
102 	CloseOnDestruct = true;
103 	Length = CalcFileLen();
104 	return true;
105 }
106 
107 
ResetFilePtr()108 void FileReader::ResetFilePtr ()
109 {
110 	FilePos = ftell (File);
111 }
112 
Tell() const113 long FileReader::Tell () const
114 {
115 	return FilePos - StartPos;
116 }
117 
Seek(long offset,int origin)118 long FileReader::Seek (long offset, int origin)
119 {
120 	if (origin == SEEK_SET)
121 	{
122 		offset += StartPos;
123 	}
124 	else if (origin == SEEK_CUR)
125 	{
126 		offset += FilePos;
127 	}
128 	else if (origin == SEEK_END)
129 	{
130 		offset += StartPos + Length;
131 	}
132 	if (0 == fseek (File, offset, SEEK_SET))
133 	{
134 		FilePos = offset;
135 		return 0;
136 	}
137 	return -1;
138 }
139 
Read(void * buffer,long len)140 long FileReader::Read (void *buffer, long len)
141 {
142 	assert(len >= 0);
143 	if (len <= 0) return 0;
144 	if (FilePos + len > StartPos + Length)
145 	{
146 		len = Length - FilePos + StartPos;
147 	}
148 	len = (long)fread (buffer, 1, len, File);
149 	FilePos += len;
150 	return len;
151 }
152 
Gets(char * strbuf,int len)153 char *FileReader::Gets(char *strbuf, int len)
154 {
155 	if (len <= 0 || FilePos >= StartPos + Length) return NULL;
156 	char *p = fgets(strbuf, len, File);
157 	if (p != NULL)
158 	{
159 		int old = FilePos;
160 		FilePos = ftell(File);
161 		if (FilePos - StartPos > Length)
162 		{
163 			strbuf[Length - old + StartPos] = 0;
164 		}
165 	}
166 	return p;
167 }
168 
GetsFromBuffer(const char * bufptr,char * strbuf,int len)169 char *FileReader::GetsFromBuffer(const char * bufptr, char *strbuf, int len)
170 {
171 	if (len>Length-FilePos) len=Length-FilePos;
172 	if (len <= 0) return NULL;
173 
174 	char *p = strbuf;
175 	while (len > 1)
176 	{
177 		if (bufptr[FilePos] == 0)
178 		{
179 			FilePos++;
180 			break;
181 		}
182 		if (bufptr[FilePos] != '\r')
183 		{
184 			*p++ = bufptr[FilePos];
185 			len--;
186 			if (bufptr[FilePos] == '\n')
187 			{
188 				FilePos++;
189 				break;
190 			}
191 		}
192 		FilePos++;
193 	}
194 	if (p==strbuf) return NULL;
195 	*p++=0;
196 	return strbuf;
197 }
198 
CalcFileLen() const199 long FileReader::CalcFileLen() const
200 {
201 	long endpos;
202 
203 	fseek (File, 0, SEEK_END);
204 	endpos = ftell (File);
205 	fseek (File, 0, SEEK_SET);
206 	return endpos;
207 }
208 
209 //==========================================================================
210 //
211 // FileReaderZ
212 //
213 // The zlib wrapper
214 // reads data from a ZLib compressed stream
215 //
216 //==========================================================================
217 
FileReaderZ(FileReader & file,bool zip)218 FileReaderZ::FileReaderZ (FileReader &file, bool zip)
219 : File(file), SawEOF(false)
220 {
221 	int err;
222 
223 	FillBuffer ();
224 
225 	Stream.zalloc = Z_NULL;
226 	Stream.zfree = Z_NULL;
227 
228 	if (!zip) err = inflateInit (&Stream);
229 	else err = inflateInit2 (&Stream, -MAX_WBITS);
230 
231 	if (err != Z_OK)
232 	{
233 		I_Error ("FileReaderZ: inflateInit failed: %s\n", M_ZLibError(err).GetChars());
234 	}
235 }
236 
~FileReaderZ()237 FileReaderZ::~FileReaderZ ()
238 {
239 	inflateEnd (&Stream);
240 }
241 
Read(void * buffer,long len)242 long FileReaderZ::Read (void *buffer, long len)
243 {
244 	int err;
245 
246 	Stream.next_out = (Bytef *)buffer;
247 	Stream.avail_out = len;
248 
249 	do
250 	{
251 		err = inflate (&Stream, Z_SYNC_FLUSH);
252 		if (Stream.avail_in == 0 && !SawEOF)
253 		{
254 			FillBuffer ();
255 		}
256 	} while (err == Z_OK && Stream.avail_out != 0);
257 
258 	if (err != Z_OK && err != Z_STREAM_END)
259 	{
260 		I_Error ("Corrupt zlib stream");
261 	}
262 
263 	if (Stream.avail_out != 0)
264 	{
265 		I_Error ("Ran out of data in zlib stream");
266 	}
267 
268 	return len - Stream.avail_out;
269 }
270 
FillBuffer()271 void FileReaderZ::FillBuffer ()
272 {
273 	long numread = File.Read (InBuff, BUFF_SIZE);
274 
275 	if (numread < BUFF_SIZE)
276 	{
277 		SawEOF = true;
278 	}
279 	Stream.next_in = InBuff;
280 	Stream.avail_in = numread;
281 }
282 
283 //==========================================================================
284 //
285 // FileReaderZ
286 //
287 // The bzip2 wrapper
288 // reads data from a libbzip2 compressed stream
289 //
290 //==========================================================================
291 
FileReaderBZ2(FileReader & file)292 FileReaderBZ2::FileReaderBZ2 (FileReader &file)
293 : File(file), SawEOF(false)
294 {
295 	int err;
296 
297 	FillBuffer ();
298 
299 	Stream.bzalloc = NULL;
300 	Stream.bzfree = NULL;
301 	Stream.opaque = NULL;
302 
303 	err = BZ2_bzDecompressInit(&Stream, 0, 0);
304 
305 	if (err != BZ_OK)
306 	{
307 		I_Error ("FileReaderBZ2: bzDecompressInit failed: %d\n", err);
308 	}
309 }
310 
~FileReaderBZ2()311 FileReaderBZ2::~FileReaderBZ2 ()
312 {
313 	BZ2_bzDecompressEnd (&Stream);
314 }
315 
Read(void * buffer,long len)316 long FileReaderBZ2::Read (void *buffer, long len)
317 {
318 	int err;
319 
320 	Stream.next_out = (char *)buffer;
321 	Stream.avail_out = len;
322 
323 	do
324 	{
325 		err = BZ2_bzDecompress(&Stream);
326 		if (Stream.avail_in == 0 && !SawEOF)
327 		{
328 			FillBuffer ();
329 		}
330 	} while (err == BZ_OK && Stream.avail_out != 0);
331 
332 	if (err != BZ_OK && err != BZ_STREAM_END)
333 	{
334 		I_Error ("Corrupt bzip2 stream");
335 	}
336 
337 	if (Stream.avail_out != 0)
338 	{
339 		I_Error ("Ran out of data in bzip2 stream");
340 	}
341 
342 	return len - Stream.avail_out;
343 }
344 
FillBuffer()345 void FileReaderBZ2::FillBuffer ()
346 {
347 	long numread = File.Read(InBuff, BUFF_SIZE);
348 
349 	if (numread < BUFF_SIZE)
350 	{
351 		SawEOF = true;
352 	}
353 	Stream.next_in = (char *)InBuff;
354 	Stream.avail_in = numread;
355 }
356 
357 //==========================================================================
358 //
359 // bz_internal_error
360 //
361 // libbzip2 wants this, since we build it with BZ_NO_STDIO set.
362 //
363 //==========================================================================
364 
bz_internal_error(int errcode)365 extern "C" void bz_internal_error (int errcode)
366 {
367 	I_FatalError("libbzip2: internal error number %d\n", errcode);
368 }
369 
370 //==========================================================================
371 //
372 // FileReaderLZMA
373 //
374 // The lzma wrapper
375 // reads data from a LZMA compressed stream
376 //
377 //==========================================================================
378 
379 // This is retarded but necessary to work around the inclusion of windows.h in recent
380 // LZMA versions, meaning it's no longer possible to include the LZMA headers in files.h.
381 // As a result we cannot declare the CLzmaDec member in the header so we work around
382 // it my wrapping it into another struct that can be declared anonymously in the header.
383 struct FileReaderLZMA::StreamPointer
384 {
385 	CLzmaDec Stream;
386 };
387 
SzAlloc(void *,size_t size)388 static void *SzAlloc(void *, size_t size) { return malloc(size); }
SzFree(void *,void * address)389 static void SzFree(void *, void *address) { free(address); }
390 ISzAlloc g_Alloc = { SzAlloc, SzFree };
391 
FileReaderLZMA(FileReader & file,size_t uncompressed_size,bool zip)392 FileReaderLZMA::FileReaderLZMA (FileReader &file, size_t uncompressed_size, bool zip)
393 : File(file), SawEOF(false)
394 {
395 	BYTE header[4 + LZMA_PROPS_SIZE];
396 	int err;
397 
398 	assert(zip == true);
399 
400 	Size = uncompressed_size;
401 	OutProcessed = 0;
402 
403 	// Read zip LZMA properties header
404 	if (File.Read(header, sizeof(header)) < (long)sizeof(header))
405 	{
406 		I_Error("FileReaderLZMA: File too shart\n");
407 	}
408 	if (header[2] + header[3] * 256 != LZMA_PROPS_SIZE)
409 	{
410 		I_Error("FileReaderLZMA: LZMA props size is %d (expected %d)\n",
411 			header[2] + header[3] * 256, LZMA_PROPS_SIZE);
412 	}
413 
414 	FillBuffer();
415 
416 	Streamp = new StreamPointer;
417 	LzmaDec_Construct(&Streamp->Stream);
418 	err = LzmaDec_Allocate(&Streamp->Stream, header + 4, LZMA_PROPS_SIZE, &g_Alloc);
419 
420 	if (err != SZ_OK)
421 	{
422 		I_Error("FileReaderLZMA: LzmaDec_Allocate failed: %d\n", err);
423 	}
424 
425 	LzmaDec_Init(&Streamp->Stream);
426 }
427 
~FileReaderLZMA()428 FileReaderLZMA::~FileReaderLZMA ()
429 {
430 	LzmaDec_Free(&Streamp->Stream, &g_Alloc);
431 	delete Streamp;
432 }
433 
Read(void * buffer,long len)434 long FileReaderLZMA::Read (void *buffer, long len)
435 {
436 	int err;
437 	Byte *next_out = (Byte *)buffer;
438 
439 	do
440 	{
441 		ELzmaFinishMode finish_mode = LZMA_FINISH_ANY;
442 		ELzmaStatus status;
443 		size_t out_processed = len;
444 		size_t in_processed = InSize;
445 
446 		err = LzmaDec_DecodeToBuf(&Streamp->Stream, next_out, &out_processed, InBuff + InPos, &in_processed, finish_mode, &status);
447 		InPos += in_processed;
448 		InSize -= in_processed;
449 		next_out += out_processed;
450 		len = (long)(len - out_processed);
451 		if (err != SZ_OK)
452 		{
453 			I_Error ("Corrupt LZMA stream");
454 		}
455 		if (in_processed == 0 && out_processed == 0)
456 		{
457 			if (status != LZMA_STATUS_FINISHED_WITH_MARK)
458 			{
459 				I_Error ("Corrupt LZMA stream");
460 			}
461 		}
462 		if (InSize == 0 && !SawEOF)
463 		{
464 			FillBuffer ();
465 		}
466 	} while (err == SZ_OK && len != 0);
467 
468 	if (err != Z_OK && err != Z_STREAM_END)
469 	{
470 		I_Error ("Corrupt LZMA stream");
471 	}
472 
473 	if (len != 0)
474 	{
475 		I_Error ("Ran out of data in LZMA stream");
476 	}
477 
478 	return (long)(next_out - (Byte *)buffer);
479 }
480 
FillBuffer()481 void FileReaderLZMA::FillBuffer ()
482 {
483 	long numread = File.Read(InBuff, BUFF_SIZE);
484 
485 	if (numread < BUFF_SIZE)
486 	{
487 		SawEOF = true;
488 	}
489 	InPos = 0;
490 	InSize = numread;
491 }
492 
493 //==========================================================================
494 //
495 // MemoryReader
496 //
497 // reads data from a block of memory
498 //
499 //==========================================================================
500 
MemoryReader(const char * buffer,long length)501 MemoryReader::MemoryReader (const char *buffer, long length)
502 {
503 	bufptr=buffer;
504 	Length=length;
505 	FilePos=0;
506 }
507 
~MemoryReader()508 MemoryReader::~MemoryReader ()
509 {
510 }
511 
Tell() const512 long MemoryReader::Tell () const
513 {
514 	return FilePos;
515 }
516 
Seek(long offset,int origin)517 long MemoryReader::Seek (long offset, int origin)
518 {
519 	switch (origin)
520 	{
521 	case SEEK_CUR:
522 		offset+=FilePos;
523 		break;
524 
525 	case SEEK_END:
526 		offset+=Length;
527 		break;
528 
529 	}
530 	FilePos=clamp<long>(offset,0,Length-1);
531 	return 0;
532 }
533 
Read(void * buffer,long len)534 long MemoryReader::Read (void *buffer, long len)
535 {
536 	if (len>Length-FilePos) len=Length-FilePos;
537 	if (len<0) len=0;
538 	memcpy(buffer,bufptr+FilePos,len);
539 	FilePos+=len;
540 	return len;
541 }
542 
Gets(char * strbuf,int len)543 char *MemoryReader::Gets(char *strbuf, int len)
544 {
545 	return GetsFromBuffer(bufptr, strbuf, len);
546 }
547 
548 //==========================================================================
549 //
550 // MemoryArrayReader
551 //
552 // reads data from an array of memory
553 //
554 //==========================================================================
555 
MemoryArrayReader(const char * buffer,long length)556 MemoryArrayReader::MemoryArrayReader (const char *buffer, long length)
557 {
558     buf.Resize(length);
559     memcpy(&buf[0], buffer, length);
560     Length=length;
561     FilePos=0;
562 }
563 
~MemoryArrayReader()564 MemoryArrayReader::~MemoryArrayReader ()
565 {
566 }
567 
Tell() const568 long MemoryArrayReader::Tell () const
569 {
570     return FilePos;
571 }
572 
Seek(long offset,int origin)573 long MemoryArrayReader::Seek (long offset, int origin)
574 {
575     switch (origin)
576     {
577     case SEEK_CUR:
578         offset+=FilePos;
579         break;
580 
581     case SEEK_END:
582         offset+=Length;
583         break;
584 
585     }
586     FilePos=clamp<long>(offset,0,Length-1);
587     return 0;
588 }
589 
Read(void * buffer,long len)590 long MemoryArrayReader::Read (void *buffer, long len)
591 {
592     if (len>Length-FilePos) len=Length-FilePos;
593     if (len<0) len=0;
594     memcpy(buffer,&buf[FilePos],len);
595     FilePos+=len;
596     return len;
597 }
598 
Gets(char * strbuf,int len)599 char *MemoryArrayReader::Gets(char *strbuf, int len)
600 {
601     return GetsFromBuffer((char*)&buf[0], strbuf, len);
602 }
603