]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/framework/File.cpp
hello world
[icculus/iodoom3.git] / neo / framework / File.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "Unzip.h"
33
34 #define MAX_PRINT_MSG           4096
35
36 /*
37 =================
38 FS_WriteFloatString
39 =================
40 */
41 int FS_WriteFloatString( char *buf, const char *fmt, va_list argPtr ) {
42         long i;
43         unsigned long u;
44         double f;
45         char *str;
46         int index;
47         idStr tmp, format;
48
49         index = 0;
50
51         while( *fmt ) {
52                 switch( *fmt ) {
53                         case '%':
54                                 format = "";
55                                 format += *fmt++;
56                                 while ( (*fmt >= '0' && *fmt <= '9') ||
57                                                 *fmt == '.' || *fmt == '-' || *fmt == '+' || *fmt == '#') {
58                                         format += *fmt++;
59                                 }
60                                 format += *fmt;
61                                 switch( *fmt ) {
62                                         case 'f':
63                                         case 'e':
64                                         case 'E':
65                                         case 'g':
66                                         case 'G':
67                                                 f = va_arg( argPtr, double );
68                                                 if ( format.Length() <= 2 ) {
69                                                         // high precision floating point number without trailing zeros
70                                                         sprintf( tmp, "%1.10f", f );
71                                                         tmp.StripTrailing( '0' );
72                                                         tmp.StripTrailing( '.' );
73                                                         index += sprintf( buf+index, "%s", tmp.c_str() );
74                                                 }
75                                                 else {
76                                                         index += sprintf( buf+index, format.c_str(), f );
77                                                 }
78                                                 break;
79                                         case 'd':
80                                         case 'i':
81                                                 i = va_arg( argPtr, long );
82                                                 index += sprintf( buf+index, format.c_str(), i );
83                                                 break;
84                                         case 'u':
85                                                 u = va_arg( argPtr, unsigned long );
86                                                 index += sprintf( buf+index, format.c_str(), u );
87                                                 break;
88                                         case 'o':
89                                                 u = va_arg( argPtr, unsigned long );
90                                                 index += sprintf( buf+index, format.c_str(), u );
91                                                 break;
92                                         case 'x':
93                                                 u = va_arg( argPtr, unsigned long );
94                                                 index += sprintf( buf+index, format.c_str(), u );
95                                                 break;
96                                         case 'X':
97                                                 u = va_arg( argPtr, unsigned long );
98                                                 index += sprintf( buf+index, format.c_str(), u );
99                                                 break;
100                                         case 'c':
101                                                 i = va_arg( argPtr, long );
102                                                 index += sprintf( buf+index, format.c_str(), (char) i );
103                                                 break;
104                                         case 's':
105                                                 str = va_arg( argPtr, char * );
106                                                 index += sprintf( buf+index, format.c_str(), str );
107                                                 break;
108                                         case '%':
109                                                 index += sprintf( buf+index, format.c_str() );
110                                                 break;
111                                         default:
112                                                 common->Error( "FS_WriteFloatString: invalid format %s", format.c_str() );
113                                                 break;
114                                 }
115                                 fmt++;
116                                 break;
117                         case '\\':
118                                 fmt++;
119                                 switch( *fmt ) {
120                                         case 't':
121                                                 index += sprintf( buf+index, "\t" );
122                                                 break;
123                                         case 'v':
124                                                 index += sprintf( buf+index, "\v" );
125                                                 break;
126                                         case 'n':
127                                                 index += sprintf( buf+index, "\n" );
128                                                 break;
129                                         case '\\':
130                                                 index += sprintf( buf+index, "\\" );
131                                                 break;
132                                         default:
133                                                 common->Error( "FS_WriteFloatString: unknown escape character \'%c\'", *fmt );
134                                                 break;
135                                 }
136                                 fmt++;
137                                 break;
138                         default:
139                                 index += sprintf( buf+index, "%c", *fmt );
140                                 fmt++;
141                                 break;
142                 }
143         }
144
145         return index;
146 }
147
148 /*
149 =================================================================================
150
151 idFile
152
153 =================================================================================
154 */
155
156 /*
157 =================
158 idFile::GetName
159 =================
160 */
161 const char *idFile::GetName( void ) {
162         return "";
163 }
164
165 /*
166 =================
167 idFile::GetFullPath
168 =================
169 */
170 const char *idFile::GetFullPath( void ) {
171         return "";
172 }
173
174 /*
175 =================
176 idFile::Read
177 =================
178 */
179 int idFile::Read( void *buffer, int len ) {
180         common->FatalError( "idFile::Read: cannot read from idFile" );
181         return 0;
182 }
183
184 /*
185 =================
186 idFile::Write
187 =================
188 */
189 int idFile::Write( const void *buffer, int len ) {
190         common->FatalError( "idFile::Write: cannot write to idFile" );
191         return 0;
192 }
193
194 /*
195 =================
196 idFile::Length
197 =================
198 */
199 int idFile::Length( void ) {
200         return 0;
201 }
202
203 /*
204 =================
205 idFile::Timestamp
206 =================
207 */
208 ID_TIME_T idFile::Timestamp( void ) {
209         return 0;
210 }
211
212 /*
213 =================
214 idFile::Tell
215 =================
216 */
217 int idFile::Tell( void ) {
218         return 0;
219 }
220
221 /*
222 =================
223 idFile::ForceFlush
224 =================
225 */
226 void idFile::ForceFlush( void ) {
227 }
228
229 /*
230 =================
231 idFile::Flush
232 =================
233 */
234 void idFile::Flush( void ) {
235 }
236
237 /*
238 =================
239 idFile::Seek
240 =================
241 */
242 int idFile::Seek( long offset, fsOrigin_t origin ) {
243         return -1;
244 }
245
246 /*
247 =================
248 idFile::Rewind
249 =================
250 */
251 void idFile::Rewind( void ) {
252         Seek( 0, FS_SEEK_SET );
253 }
254
255 /*
256 =================
257 idFile::Printf
258 =================
259 */
260 int idFile::Printf( const char *fmt, ... ) {
261         char buf[MAX_PRINT_MSG];
262         int length;
263         va_list argptr;
264
265         va_start( argptr, fmt );
266         length = idStr::vsnPrintf( buf, MAX_PRINT_MSG-1, fmt, argptr );
267         va_end( argptr );
268
269         // so notepad formats the lines correctly
270         idStr   work( buf );
271         work.Replace( "\n", "\r\n" );
272   
273         return Write( work.c_str(), work.Length() );
274 }
275
276 /*
277 =================
278 idFile::VPrintf
279 =================
280 */
281 int idFile::VPrintf( const char *fmt, va_list args ) {
282         char buf[MAX_PRINT_MSG];
283         int length;
284
285         length = idStr::vsnPrintf( buf, MAX_PRINT_MSG-1, fmt, args );
286         return Write( buf, length );
287 }
288
289 /*
290 =================
291 idFile::WriteFloatString
292 =================
293 */
294 int idFile::WriteFloatString( const char *fmt, ... ) {
295         char buf[MAX_PRINT_MSG];
296         int len;
297         va_list argPtr;
298
299         va_start( argPtr, fmt );
300         len = FS_WriteFloatString( buf, fmt, argPtr );
301         va_end( argPtr );
302
303         return Write( buf, len );
304 }
305
306 /*
307  =================
308  idFile::ReadInt
309  =================
310  */
311 int idFile::ReadInt( int &value ) {
312         int result = Read( &value, sizeof( value ) );
313         value = LittleLong(value);
314         return result;
315 }
316
317 /*
318  =================
319  idFile::ReadUnsignedInt
320  =================
321  */
322 int idFile::ReadUnsignedInt( unsigned int &value ) {
323         int result = Read( &value, sizeof( value ) );
324         value = LittleLong(value);
325         return result;
326 }
327
328 /*
329  =================
330  idFile::ReadShort
331  =================
332  */
333 int idFile::ReadShort( short &value ) {
334         int result = Read( &value, sizeof( value ) );
335         value = LittleShort(value);
336         return result;
337 }
338
339 /*
340  =================
341  idFile::ReadUnsignedShort
342  =================
343  */
344 int idFile::ReadUnsignedShort( unsigned short &value ) {
345         int result = Read( &value, sizeof( value ) );
346         value = LittleShort(value);
347         return result;
348 }
349
350 /*
351  =================
352  idFile::ReadChar
353  =================
354  */
355 int idFile::ReadChar( char &value ) {
356         return Read( &value, sizeof( value ) );
357 }
358
359 /*
360  =================
361  idFile::ReadUnsignedChar
362  =================
363  */
364 int idFile::ReadUnsignedChar( unsigned char &value ) {
365         return Read( &value, sizeof( value ) );
366 }
367
368 /*
369  =================
370  idFile::ReadFloat
371  =================
372  */
373 int idFile::ReadFloat( float &value ) {
374         int result = Read( &value, sizeof( value ) );
375         value = LittleFloat(value);
376         return result;
377 }
378
379 /*
380  =================
381  idFile::ReadBool
382  =================
383  */
384 int idFile::ReadBool( bool &value ) {
385         unsigned char c;
386         int result = ReadUnsignedChar( c );
387         value = c ? true : false;
388         return result;
389 }
390
391 /*
392  =================
393  idFile::ReadString
394  =================
395  */
396 int idFile::ReadString( idStr &string ) {
397         int len;
398         int result = 0;
399         
400         ReadInt( len );
401         if ( len >= 0 ) {
402                 string.Fill( ' ', len );
403                 result = Read( &string[ 0 ], len );
404         }
405         return result;
406 }
407
408 /*
409  =================
410  idFile::ReadVec2
411  =================
412  */
413 int idFile::ReadVec2( idVec2 &vec ) {
414         int result = Read( &vec, sizeof( vec ) );
415         LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) );
416         return result;
417 }
418
419 /*
420  =================
421  idFile::ReadVec3
422  =================
423  */
424 int idFile::ReadVec3( idVec3 &vec ) {
425         int result = Read( &vec, sizeof( vec ) );
426         LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) );
427         return result;
428 }
429
430 /*
431  =================
432  idFile::ReadVec4
433  =================
434  */
435 int idFile::ReadVec4( idVec4 &vec ) {
436         int result = Read( &vec, sizeof( vec ) );
437         LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) );
438         return result;
439 }
440
441 /*
442  =================
443  idFile::ReadVec6
444  =================
445  */
446 int idFile::ReadVec6( idVec6 &vec ) {
447         int result = Read( &vec, sizeof( vec ) );
448         LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) );
449         return result;
450 }
451
452 /*
453  =================
454  idFile::ReadMat3
455  =================
456  */
457 int idFile::ReadMat3( idMat3 &mat ) {
458         int result = Read( &mat, sizeof( mat ) );
459         LittleRevBytes( &mat, sizeof(float), sizeof(mat)/sizeof(float) );
460         return result;
461 }
462
463 /*
464  =================
465  idFile::WriteInt
466  =================
467  */
468 int idFile::WriteInt( const int value ) {
469         int v = LittleLong(value);
470         return Write( &v, sizeof( v ) );
471 }
472
473 /*
474  =================
475  idFile::WriteUnsignedInt
476  =================
477  */
478 int idFile::WriteUnsignedInt( const unsigned int value ) {
479         unsigned int v = LittleLong(value);
480         return Write( &v, sizeof( v ) );
481 }
482
483 /*
484  =================
485  idFile::WriteShort
486  =================
487  */
488 int idFile::WriteShort( const short value ) {
489         short v = LittleShort(value);
490         return Write( &v, sizeof( v ) );
491 }
492
493 /*
494  =================
495  idFile::WriteUnsignedShort
496  =================
497  */
498 int idFile::WriteUnsignedShort( const unsigned short value ) {
499         unsigned short v = LittleShort(value);
500         return Write( &v, sizeof( v ) );
501 }
502
503 /*
504  =================
505  idFile::WriteChar
506  =================
507  */
508 int idFile::WriteChar( const char value ) {
509         return Write( &value, sizeof( value ) );
510 }
511
512 /*
513  =================
514  idFile::WriteUnsignedChar
515  =================
516  */
517 int idFile::WriteUnsignedChar( const unsigned char value ) {
518         return Write( &value, sizeof( value ) );
519 }
520
521 /*
522  =================
523  idFile::WriteFloat
524  =================
525  */
526 int idFile::WriteFloat( const float value ) {
527         float v = LittleFloat(value);
528         return Write( &v, sizeof( v ) );
529 }
530
531 /*
532  =================
533  idFile::WriteBool
534  =================
535  */
536 int idFile::WriteBool( const bool value ) {
537         unsigned char c = value;
538         return WriteUnsignedChar( c );
539 }
540
541 /*
542  =================
543  idFile::WriteString
544  =================
545  */
546 int idFile::WriteString( const char *value ) {
547         int len;
548         
549         len = strlen( value );
550         WriteInt( len );
551     return Write( value, len );
552 }
553
554 /*
555  =================
556  idFile::WriteVec2
557  =================
558  */
559 int idFile::WriteVec2( const idVec2 &vec ) {
560         idVec2 v = vec;
561         LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) );
562         return Write( &v, sizeof( v ) );
563 }
564
565 /*
566  =================
567  idFile::WriteVec3
568  =================
569  */
570 int idFile::WriteVec3( const idVec3 &vec ) {
571         idVec3 v = vec;
572         LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) );
573         return Write( &v, sizeof( v ) );
574 }
575
576 /*
577  =================
578  idFile::WriteVec4
579  =================
580  */
581 int idFile::WriteVec4( const idVec4 &vec ) {
582         idVec4 v = vec;
583         LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) );
584         return Write( &v, sizeof( v ) );
585 }
586
587 /*
588  =================
589  idFile::WriteVec6
590  =================
591  */
592 int idFile::WriteVec6( const idVec6 &vec ) {
593         idVec6 v = vec;
594         LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) );
595         return Write( &v, sizeof( v ) );
596 }
597
598 /*
599  =================
600  idFile::WriteMat3
601  =================
602  */
603 int idFile::WriteMat3( const idMat3 &mat ) {
604         idMat3 v = mat;
605         LittleRevBytes(&v, sizeof(float), sizeof(v)/sizeof(float) );
606         return Write( &v, sizeof( v ) );
607 }
608
609 /*
610 =================================================================================
611
612 idFile_Memory
613
614 =================================================================================
615 */
616
617
618 /*
619 =================
620 idFile_Memory::idFile_Memory
621 =================
622 */
623 idFile_Memory::idFile_Memory( void ) {
624         name = "*unknown*";
625         maxSize = 0;
626         fileSize = 0;
627         allocated = 0;
628         granularity = 16384;
629
630         mode = ( 1 << FS_WRITE );
631         filePtr = NULL;
632         curPtr = NULL;
633 }
634
635 /*
636 =================
637 idFile_Memory::idFile_Memory
638 =================
639 */
640 idFile_Memory::idFile_Memory( const char *name ) {
641         this->name = name;
642         maxSize = 0;
643         fileSize = 0;
644         allocated = 0;
645         granularity = 16384;
646
647         mode = ( 1 << FS_WRITE );
648         filePtr = NULL;
649         curPtr = NULL;
650 }
651
652 /*
653 =================
654 idFile_Memory::idFile_Memory
655 =================
656 */
657 idFile_Memory::idFile_Memory( const char *name, char *data, int length ) {
658         this->name = name;
659         maxSize = length;
660         fileSize = 0;
661         allocated = length;
662         granularity = 16384;
663
664         mode = ( 1 << FS_WRITE );
665         filePtr = data;
666         curPtr = data;
667 }
668
669 /*
670 =================
671 idFile_Memory::idFile_Memory
672 =================
673 */
674 idFile_Memory::idFile_Memory( const char *name, const char *data, int length ) {
675         this->name = name;
676         maxSize = 0;
677         fileSize = length;
678         allocated = 0;
679         granularity = 16384;
680
681         mode = ( 1 << FS_READ );
682         filePtr = const_cast<char *>(data);
683         curPtr = const_cast<char *>(data);
684 }
685
686 /*
687 =================
688 idFile_Memory::~idFile_Memory
689 =================
690 */
691 idFile_Memory::~idFile_Memory( void ) {
692         if ( filePtr && allocated > 0 && maxSize == 0 ) {
693                 Mem_Free( filePtr );
694         }
695 }
696
697 /*
698 =================
699 idFile_Memory::Read
700 =================
701 */
702 int idFile_Memory::Read( void *buffer, int len ) {
703
704         if ( !( mode & ( 1 << FS_READ ) ) ) {
705                 common->FatalError( "idFile_Memory::Read: %s not opened in read mode", name.c_str() );
706                 return 0;
707         }
708
709         if ( curPtr + len > filePtr + fileSize ) {
710                 len = filePtr + fileSize - curPtr;
711         }
712         memcpy( buffer, curPtr, len );
713         curPtr += len;
714         return len;
715 }
716
717 /*
718 =================
719 idFile_Memory::Write
720 =================
721 */
722 int idFile_Memory::Write( const void *buffer, int len ) {
723
724         if ( !( mode & ( 1 << FS_WRITE ) ) ) {
725                 common->FatalError( "idFile_Memory::Write: %s not opened in write mode", name.c_str() );
726                 return 0;
727         }
728
729         int alloc = curPtr + len + 1 - filePtr - allocated; // need room for len+1
730         if ( alloc > 0 ) {
731                 if ( maxSize != 0 ) {
732                         common->Error( "idFile_Memory::Write: exceeded maximum size %d", maxSize );
733                         return 0;
734                 }
735                 int extra = granularity * ( 1 + alloc / granularity );
736                 char *newPtr = (char *) Mem_Alloc( allocated + extra );
737                 if ( allocated ) {
738                         memcpy( newPtr, filePtr, allocated );
739                 }
740                 allocated += extra;
741                 curPtr = newPtr + ( curPtr - filePtr );         
742                 if ( filePtr ) {
743                         Mem_Free( filePtr );
744                 }
745                 filePtr = newPtr;
746         }
747         memcpy( curPtr, buffer, len );
748         curPtr += len;
749         fileSize += len;
750         filePtr[ fileSize ] = 0; // len + 1
751         return len;
752 }
753
754 /*
755 =================
756 idFile_Memory::Length
757 =================
758 */
759 int idFile_Memory::Length( void ) {
760         return fileSize;
761 }
762
763 /*
764 =================
765 idFile_Memory::Timestamp
766 =================
767 */
768 ID_TIME_T idFile_Memory::Timestamp( void ) {
769         return 0;
770 }
771
772 /*
773 =================
774 idFile_Memory::Tell
775 =================
776 */
777 int idFile_Memory::Tell( void ) {
778         return ( curPtr - filePtr );
779 }
780
781 /*
782 =================
783 idFile_Memory::ForceFlush
784 =================
785 */
786 void idFile_Memory::ForceFlush( void ) {
787 }
788
789 /*
790 =================
791 idFile_Memory::Flush
792 =================
793 */
794 void idFile_Memory::Flush( void ) {
795 }
796
797 /*
798 =================
799 idFile_Memory::Seek
800
801   returns zero on success and -1 on failure
802 =================
803 */
804 int idFile_Memory::Seek( long offset, fsOrigin_t origin ) {
805
806         switch( origin ) {
807                 case FS_SEEK_CUR: {
808                         curPtr += offset;
809                         break;
810                 }
811                 case FS_SEEK_END: {
812                         curPtr = filePtr + fileSize - offset;
813                         break;
814                 }
815                 case FS_SEEK_SET: {
816                         curPtr = filePtr + offset;
817                         break;
818                 }
819                 default: {
820                         common->FatalError( "idFile_Memory::Seek: bad origin for %s\n", name.c_str() );
821                         return -1;
822                 }
823         }
824         if ( curPtr < filePtr ) {
825                 curPtr = filePtr;
826                 return -1;
827         }
828         if ( curPtr > filePtr + fileSize ) {
829                 curPtr = filePtr + fileSize;
830                 return -1;
831         }
832         return 0;
833 }
834
835 /*
836 =================
837 idFile_Memory::MakeReadOnly
838 =================
839 */
840 void idFile_Memory::MakeReadOnly( void ) {
841         mode = ( 1 << FS_READ );
842         Rewind();
843 }
844
845 /*
846 =================
847 idFile_Memory::Clear
848 =================
849 */
850 void idFile_Memory::Clear( bool freeMemory ) {
851         fileSize = 0;
852         granularity = 16384;
853         if ( freeMemory ) {
854                 allocated = 0;
855                 Mem_Free( filePtr );
856                 filePtr = NULL;
857                 curPtr = NULL;
858         } else {
859                 curPtr = filePtr;
860         }
861 }
862
863 /*
864 =================
865 idFile_Memory::SetData
866 =================
867 */
868 void idFile_Memory::SetData( const char *data, int length ) {
869         maxSize = 0;
870         fileSize = length;
871         allocated = 0;
872         granularity = 16384;
873
874         mode = ( 1 << FS_READ );
875         filePtr = const_cast<char *>(data);
876         curPtr = const_cast<char *>(data);
877 }
878
879
880 /*
881 =================================================================================
882
883 idFile_BitMsg
884
885 =================================================================================
886 */
887
888 /*
889 =================
890 idFile_BitMsg::idFile_BitMsg
891 =================
892 */
893 idFile_BitMsg::idFile_BitMsg( idBitMsg &msg ) {
894         name = "*unknown*";
895         mode = ( 1 << FS_WRITE );
896         this->msg = &msg;
897 }
898
899 /*
900 =================
901 idFile_BitMsg::idFile_BitMsg
902 =================
903 */
904 idFile_BitMsg::idFile_BitMsg( const idBitMsg &msg ) {
905         name = "*unknown*";
906         mode = ( 1 << FS_READ );
907         this->msg = const_cast<idBitMsg *>(&msg);
908 }
909
910 /*
911 =================
912 idFile_BitMsg::~idFile_BitMsg
913 =================
914 */
915 idFile_BitMsg::~idFile_BitMsg( void ) {
916 }
917
918 /*
919 =================
920 idFile_BitMsg::Read
921 =================
922 */
923 int idFile_BitMsg::Read( void *buffer, int len ) {
924
925         if ( !( mode & ( 1 << FS_READ ) ) ) {
926                 common->FatalError( "idFile_BitMsg::Read: %s not opened in read mode", name.c_str() );
927                 return 0;
928         }
929
930         return msg->ReadData( buffer, len );
931 }
932
933 /*
934 =================
935 idFile_BitMsg::Write
936 =================
937 */
938 int idFile_BitMsg::Write( const void *buffer, int len ) {
939
940         if ( !( mode & ( 1 << FS_WRITE ) ) ) {
941                 common->FatalError( "idFile_Memory::Write: %s not opened in write mode", name.c_str() );
942                 return 0;
943         }
944
945         msg->WriteData( buffer, len );
946         return len;
947 }
948
949 /*
950 =================
951 idFile_BitMsg::Length
952 =================
953 */
954 int idFile_BitMsg::Length( void ) {
955         return msg->GetSize();
956 }
957
958 /*
959 =================
960 idFile_BitMsg::Timestamp
961 =================
962 */
963 ID_TIME_T idFile_BitMsg::Timestamp( void ) {
964         return 0;
965 }
966
967 /*
968 =================
969 idFile_BitMsg::Tell
970 =================
971 */
972 int idFile_BitMsg::Tell( void ) {
973         if ( mode & FS_READ ) {
974                 return msg->GetReadCount();
975         } else {
976                 return msg->GetSize();
977         }
978 }
979
980 /*
981 =================
982 idFile_BitMsg::ForceFlush
983 =================
984 */
985 void idFile_BitMsg::ForceFlush( void ) {
986 }
987
988 /*
989 =================
990 idFile_BitMsg::Flush
991 =================
992 */
993 void idFile_BitMsg::Flush( void ) {
994 }
995
996 /*
997 =================
998 idFile_BitMsg::Seek
999
1000   returns zero on success and -1 on failure
1001 =================
1002 */
1003 int idFile_BitMsg::Seek( long offset, fsOrigin_t origin ) {
1004         return -1;
1005 }
1006
1007
1008 /*
1009 =================================================================================
1010
1011 idFile_Permanent
1012
1013 =================================================================================
1014 */
1015
1016 /*
1017 =================
1018 idFile_Permanent::idFile_Permanent
1019 =================
1020 */
1021 idFile_Permanent::idFile_Permanent( void ) {
1022         name = "invalid";
1023         o = NULL;
1024         mode = 0;
1025         fileSize = 0;
1026         handleSync = false;
1027 }
1028
1029 /*
1030 =================
1031 idFile_Permanent::~idFile_Permanent
1032 =================
1033 */
1034 idFile_Permanent::~idFile_Permanent( void ) {
1035         if ( o ) {
1036                 fclose( o );
1037         }
1038 }
1039
1040 /*
1041 =================
1042 idFile_Permanent::Read
1043
1044 Properly handles partial reads
1045 =================
1046 */
1047 int idFile_Permanent::Read( void *buffer, int len ) {
1048         int             block, remaining;
1049         int             read;
1050         byte *  buf;
1051         int             tries;
1052
1053         if ( !(mode & ( 1 << FS_READ ) ) ) {
1054                 common->FatalError( "idFile_Permanent::Read: %s not opened in read mode", name.c_str() );
1055                 return 0;
1056         }
1057
1058         if ( !o ) {
1059                 return 0;
1060         }
1061
1062         buf = (byte *)buffer;
1063
1064         remaining = len;
1065         tries = 0;
1066         while( remaining ) {
1067                 block = remaining;
1068                 read = fread( buf, 1, block, o );
1069                 if ( read == 0 ) {
1070                         // we might have been trying to read from a CD, which
1071                         // sometimes returns a 0 read on windows
1072                         if ( !tries ) {
1073                                 tries = 1;
1074                         }
1075                         else {
1076                                 fileSystem->AddToReadCount( len - remaining );
1077                                 return len-remaining;
1078                         }
1079                 }
1080
1081                 if ( read == -1 ) {
1082                         common->FatalError( "idFile_Permanent::Read: -1 bytes read from %s", name.c_str() );
1083                 }
1084
1085                 remaining -= read;
1086                 buf += read;
1087         }
1088         fileSystem->AddToReadCount( len );
1089         return len;
1090 }
1091
1092 /*
1093 =================
1094 idFile_Permanent::Write
1095
1096 Properly handles partial writes
1097 =================
1098 */
1099 int idFile_Permanent::Write( const void *buffer, int len ) {
1100         int             block, remaining;
1101         int             written;
1102         byte *  buf;
1103         int             tries;
1104
1105         if ( !( mode & ( 1 << FS_WRITE ) ) ) {
1106                 common->FatalError( "idFile_Permanent::Write: %s not opened in write mode", name.c_str() );
1107                 return 0;
1108         }
1109
1110         if ( !o ) {
1111                 return 0;
1112         }
1113
1114         buf = (byte *)buffer;
1115
1116         remaining = len;
1117         tries = 0;
1118         while( remaining ) {
1119                 block = remaining;
1120                 written = fwrite( buf, 1, block, o );
1121                 if ( written == 0 ) {
1122                         if ( !tries ) {
1123                                 tries = 1;
1124                         }
1125                         else {
1126                                 common->Printf( "idFile_Permanent::Write: 0 bytes written to %s\n", name.c_str() );
1127                                 return 0;
1128                         }
1129                 }
1130
1131                 if ( written == -1 ) {
1132                         common->Printf( "idFile_Permanent::Write: -1 bytes written to %s\n", name.c_str() );
1133                         return 0;
1134                 }
1135
1136                 remaining -= written;
1137                 buf += written;
1138                 fileSize += written;
1139         }
1140         if ( handleSync ) {
1141                 fflush( o );
1142         }
1143         return len;
1144 }
1145
1146 /*
1147 =================
1148 idFile_Permanent::ForceFlush
1149 =================
1150 */
1151 void idFile_Permanent::ForceFlush( void ) {
1152         setvbuf( o, NULL, _IONBF, 0 );
1153 }
1154
1155 /*
1156 =================
1157 idFile_Permanent::Flush
1158 =================
1159 */
1160 void idFile_Permanent::Flush( void ) {
1161         fflush( o );
1162 }
1163
1164 /*
1165 =================
1166 idFile_Permanent::Tell
1167 =================
1168 */
1169 int idFile_Permanent::Tell( void ) {
1170         return ftell( o );
1171 }
1172
1173 /*
1174 ================
1175 idFile_Permanent::Length
1176 ================
1177 */
1178 int idFile_Permanent::Length( void ) {
1179         return fileSize;
1180 }
1181
1182 /*
1183 ================
1184 idFile_Permanent::Timestamp
1185 ================
1186 */
1187 ID_TIME_T idFile_Permanent::Timestamp( void ) {
1188         return Sys_FileTimeStamp( o );
1189 }
1190
1191 /*
1192 =================
1193 idFile_Permanent::Seek
1194
1195   returns zero on success and -1 on failure
1196 =================
1197 */
1198 int idFile_Permanent::Seek( long offset, fsOrigin_t origin ) {
1199         int _origin;
1200
1201         switch( origin ) {
1202                 case FS_SEEK_CUR: {
1203                         _origin = SEEK_CUR;
1204                         break;
1205                 }
1206                 case FS_SEEK_END: {
1207                         _origin = SEEK_END;
1208                         break;
1209                 }
1210                 case FS_SEEK_SET: {
1211                         _origin = SEEK_SET;
1212                         break;
1213                 }
1214                 default: {
1215                         _origin = SEEK_CUR;
1216                         common->FatalError( "idFile_Permanent::Seek: bad origin for %s\n", name.c_str() );
1217                         break;
1218                 }
1219         }
1220
1221         return fseek( o, offset, _origin );
1222 }
1223
1224
1225 /*
1226 =================================================================================
1227
1228 idFile_InZip
1229
1230 =================================================================================
1231 */
1232
1233 /*
1234 =================
1235 idFile_InZip::idFile_InZip
1236 =================
1237 */
1238 idFile_InZip::idFile_InZip( void ) {
1239         name = "invalid";
1240         zipFilePos = 0;
1241         fileSize = 0;
1242         memset( &z, 0, sizeof( z ) );
1243 }
1244
1245 /*
1246 =================
1247 idFile_InZip::~idFile_InZip
1248 =================
1249 */
1250 idFile_InZip::~idFile_InZip( void ) {
1251         unzCloseCurrentFile( z );
1252         unzClose( z );
1253 }
1254
1255 /*
1256 =================
1257 idFile_InZip::Read
1258
1259 Properly handles partial reads
1260 =================
1261 */
1262 int idFile_InZip::Read( void *buffer, int len ) {
1263         int l = unzReadCurrentFile( z, buffer, len );
1264         fileSystem->AddToReadCount( l );
1265         return l;
1266 }
1267
1268 /*
1269 =================
1270 idFile_InZip::Write
1271 =================
1272 */
1273 int idFile_InZip::Write( const void *buffer, int len ) {
1274         common->FatalError( "idFile_InZip::Write: cannot write to the zipped file %s", name.c_str() );
1275         return 0;
1276 }
1277
1278 /*
1279 =================
1280 idFile_InZip::ForceFlush
1281 =================
1282 */
1283 void idFile_InZip::ForceFlush( void ) {
1284         common->FatalError( "idFile_InZip::ForceFlush: cannot flush the zipped file %s", name.c_str() );
1285 }
1286
1287 /*
1288 =================
1289 idFile_InZip::Flush
1290 =================
1291 */
1292 void idFile_InZip::Flush( void ) {
1293         common->FatalError( "idFile_InZip::Flush: cannot flush the zipped file %s", name.c_str() );
1294 }
1295
1296 /*
1297 =================
1298 idFile_InZip::Tell
1299 =================
1300 */
1301 int idFile_InZip::Tell( void ) {
1302         return unztell( z );
1303 }
1304
1305 /*
1306 ================
1307 idFile_InZip::Length
1308 ================
1309 */
1310 int idFile_InZip::Length( void ) {
1311         return fileSize;
1312 }
1313
1314 /*
1315 ================
1316 idFile_InZip::Timestamp
1317 ================
1318 */
1319 ID_TIME_T idFile_InZip::Timestamp( void ) {
1320         return 0;
1321 }
1322
1323 /*
1324 =================
1325 idFile_InZip::Seek
1326
1327   returns zero on success and -1 on failure
1328 =================
1329 */
1330 #define ZIP_SEEK_BUF_SIZE       (1<<15)
1331
1332 int idFile_InZip::Seek( long offset, fsOrigin_t origin ) {
1333         int res, i;
1334         char *buf;
1335
1336         switch( origin ) {
1337                 case FS_SEEK_END: {
1338                         offset = fileSize - offset;
1339                 }
1340                 case FS_SEEK_SET: {
1341                         // set the file position in the zip file (also sets the current file info)
1342                         unzSetCurrentFileInfoPosition( z, zipFilePos );
1343                         unzOpenCurrentFile( z );
1344                         if ( offset <= 0 ) {
1345                                 return 0;
1346                         }
1347                 }
1348                 case FS_SEEK_CUR: {
1349                         buf = (char *) _alloca16( ZIP_SEEK_BUF_SIZE );
1350                         for ( i = 0; i < ( offset - ZIP_SEEK_BUF_SIZE ); i += ZIP_SEEK_BUF_SIZE ) {
1351                                 res = unzReadCurrentFile( z, buf, ZIP_SEEK_BUF_SIZE );
1352                                 if ( res < ZIP_SEEK_BUF_SIZE ) {
1353                                         return -1;
1354                                 }
1355                         }
1356                         res = i + unzReadCurrentFile( z, buf, offset - i );
1357                         return ( res == offset ) ? 0 : -1;
1358                 }
1359                 default: {
1360                         common->FatalError( "idFile_InZip::Seek: bad origin for %s\n", name.c_str() );
1361                         break;
1362                 }
1363         }
1364         return -1;
1365 }