]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/common/cmdlib.c
introduce safe_malloc0, also 0 the memory before usage
[xonotic/netradiant.git] / tools / quake3 / common / cmdlib.c
1 /*
2    Copyright (C) 1999-2007 id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 // cmdlib.c
23 // TTimo 09/30/2000
24 // from an intial copy of common/cmdlib.c
25 // stripped out the Sys_Printf Sys_Printf stuff
26
27 // SPoG 05/27/2001
28 // merging alpha branch into trunk
29 // replaced qprintf with Sys_Printf
30
31 #include "cmdlib.h"
32 #include "globaldefs.h"
33 #include "mathlib.h"
34 #include "inout.h"
35 #include <sys/types.h>
36 #include <sys/stat.h>
37
38 #if GDEF_OS_WINDOWS
39 #include <direct.h>
40 #include <windows.h>
41 #elif GDEF_OS_NEXT
42 #include <libc.h>
43 #else // OTHER OS
44 #include <unistd.h>
45 #endif // OTHER OS
46
47 #define BASEDIRNAME "quake" // assumed to have a 2 or 3 following
48 #define PATHSEPERATOR '/'
49
50 void *safe_malloc( size_t size ){
51         void *p;
52
53         p = malloc( size );
54         if ( !p ) {
55                 Error( "safe_malloc failed on allocation of %i bytes", size );
56         }
57
58         return p;
59 }
60
61 void *safe_malloc_info( size_t size, char* info ){
62         void *p;
63
64         p = malloc( size );
65         if ( !p ) {
66                 Error( "%s: safe_malloc failed on allocation of %i bytes", info, size );
67         }
68
69         return p;
70 }
71
72 void *safe_malloc0( size_t size ){
73         void *p;
74
75         p = calloc( 1, size );
76         if ( !p ) {
77                 Error( "safe_malloc0 failed on allocation of %i bytes", size );
78         }
79
80         return p;
81 }
82
83 void *safe_malloc0_info( size_t size, char* info ){
84         void *p;
85
86         p = calloc( 1, size );
87         if ( !p ) {
88                 Error( "%s: safe_malloc0 failed on allocation of %i bytes", info, size );
89         }
90
91         return p;
92 }
93
94 // set these before calling CheckParm
95 int myargc;
96 char **myargv;
97
98 char com_token[1024];
99 qboolean com_eof;
100
101 qboolean archive;
102 char archivedir[1024];
103
104
105 /*
106    ===================
107    ExpandWildcards
108
109    Mimic unix command line expansion
110    ===================
111  */
112 #define MAX_EX_ARGC 1024
113 int ex_argc;
114 char    *ex_argv[MAX_EX_ARGC];
115
116 #if GDEF_OS_WINDOWS
117 #include "io.h"
118 void ExpandWildcards( int *argc, char ***argv ){
119         struct _finddata_t fileinfo;
120         int handle;
121         int i;
122         char filename[1024];
123         char filebase[1024];
124         char    *path;
125
126         ex_argc = 0;
127         for ( i = 0 ; i < *argc ; i++ )
128         {
129                 path = ( *argv )[i];
130                 if ( path[0] == '-'
131                          || ( !strstr( path, "*" ) && !strstr( path, "?" ) ) ) {
132                         ex_argv[ex_argc++] = path;
133                         continue;
134                 }
135
136                 handle = _findfirst( path, &fileinfo );
137                 if ( handle == -1 ) {
138                         return;
139                 }
140
141                 ExtractFilePath( path, filebase );
142
143                 do
144                 {
145                         sprintf( filename, "%s%s", filebase, fileinfo.name );
146                         ex_argv[ex_argc++] = copystring( filename );
147                 } while ( _findnext( handle, &fileinfo ) != -1 );
148
149                 _findclose( handle );
150         }
151
152         *argc = ex_argc;
153         *argv = ex_argv;
154 }
155 #else // !GDEF_OS_WINDOWS
156 void ExpandWildcards( int *argc, char ***argv ){
157 }
158 #endif // !GDEF_OS_WINDOWS
159
160 /*
161
162    qdir will hold the path up to the quake directory, including the slash
163
164    f:\quake\
165    /raid/quake/
166
167    gamedir will hold qdir + the game directory (id1, id2, etc)
168
169  */
170
171 char qdir[1024];
172 char gamedir[1024];
173 char writedir[1024];
174
175 void SetQdirFromPath( const char *path ){
176         char temp[1024];
177         const char  *c;
178         const char *sep;
179         int len, count;
180
181         if ( !( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) ) { // path is partial
182                 Q_getwd( temp );
183                 strcat( temp, path );
184                 path = temp;
185         }
186
187         // search for "quake2" in path
188
189         len = strlen( BASEDIRNAME );
190         for ( c = path + strlen( path ) - 1 ; c != path ; c-- )
191         {
192                 int i;
193
194                 if ( !Q_strncasecmp( c, BASEDIRNAME, len ) ) {
195                         //
196                         //strncpy (qdir, path, c+len+2-path);
197                         // the +2 assumes a 2 or 3 following quake which is not the
198                         // case with a retail install
199                         // so we need to add up how much to the next separator
200                         sep = c + len;
201                         count = 1;
202                         while ( *sep && *sep != '/' && *sep != '\\' )
203                         {
204                                 sep++;
205                                 count++;
206                         }
207                         strncpy( qdir, path, c + len + count - path );
208                         Sys_Printf( "qdir: %s\n", qdir );
209                         for ( i = 0; i < (int) strlen( qdir ); i++ )
210                         {
211                                 if ( qdir[i] == '\\' ) {
212                                         qdir[i] = '/';
213                                 }
214                         }
215
216                         c += len + count;
217                         while ( *c )
218                         {
219                                 if ( *c == '/' || *c == '\\' ) {
220                                         strncpy( gamedir, path, c + 1 - path );
221
222                                         for ( i = 0; i < (int) strlen( gamedir ); i++ )
223                                         {
224                                                 if ( gamedir[i] == '\\' ) {
225                                                         gamedir[i] = '/';
226                                                 }
227                                         }
228
229                                         Sys_Printf( "gamedir: %s\n", gamedir );
230
231                                         if ( !writedir[0] ) {
232                                                 strcpy( writedir, gamedir );
233                                         }
234                                         else if ( writedir[strlen( writedir ) - 1] != '/' ) {
235                                                 writedir[strlen( writedir )] = '/';
236                                                 writedir[strlen( writedir ) + 1] = 0;
237                                         }
238
239                                         return;
240                                 }
241                                 c++;
242                         }
243                         Error( "No gamedir in %s", path );
244                         return;
245                 }
246         }
247         Error( "SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path );
248 }
249
250 char *ExpandArg( const char *path ){
251         static char full[1024];
252
253         if ( path[0] != '/' && path[0] != '\\' && path[1] != ':' ) {
254                 Q_getwd( full );
255                 strcat( full, path );
256         }
257         else{
258                 strcpy( full, path );
259         }
260         return full;
261 }
262
263 char *ExpandPath( const char *path ){
264         static char full[1024];
265         if ( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) {
266                 strcpy( full, path );
267                 return full;
268         }
269         sprintf( full, "%s%s", qdir, path );
270         return full;
271 }
272
273 char *copystring( const char *s ){
274         char    *b;
275         b = safe_malloc( strlen( s ) + 1 );
276         strcpy( b, s );
277         return b;
278 }
279
280
281
282 /*
283    ================
284    I_FloatTime
285    ================
286  */
287 double I_FloatTime( void ){
288         time_t t;
289
290         time( &t );
291
292         return t;
293 #if 0
294 // more precise, less portable
295         struct timeval tp;
296         struct timezone tzp;
297         static int secbase;
298
299         gettimeofday( &tp, &tzp );
300
301         if ( !secbase ) {
302                 secbase = tp.tv_sec;
303                 return tp.tv_usec / 1000000.0;
304         }
305
306         return ( tp.tv_sec - secbase ) + tp.tv_usec / 1000000.0;
307 #endif
308 }
309
310 void Q_getwd( char *out ){
311         int i = 0;
312
313 #if GDEF_OS_WINDOWS
314         _getcwd( out, 256 );
315         strcat( out, "\\" );
316 #else // !GDEF_OS_WINDOWS
317         // Gef: Changed from getwd() to getcwd() to avoid potential buffer overflow
318         if ( !getcwd( out, 256 ) ) {
319                 *out = 0;
320         }
321         strcat( out, "/" );
322 #endif // !GDEF_OS_WINDOWS
323         while ( out[i] != 0 )
324         {
325                 if ( out[i] == '\\' ) {
326                         out[i] = '/';
327                 }
328                 i++;
329         }
330 }
331
332
333 void Q_mkdir( const char *path ){
334         char parentbuf[256];
335         const char *p = NULL;
336         int retry = 2;
337         while ( retry-- )
338         {
339 #if GDEF_OS_WINDOWS
340                 const char *q = NULL;
341                 if ( _mkdir( path ) != -1 ) {
342                         return;
343                 }
344                 if ( errno == ENOENT ) {
345                         p = strrchr( path, '/' );
346                         q = strrchr( path, '\\' );
347                         if ( q && ( !p || q < p ) ) {
348                                 p = q;
349                         }
350                 }
351 #else // !GDEF_OS_WINDOWS
352                 if ( mkdir( path, 0777 ) != -1 ) {
353                         return;
354                 }
355                 if ( errno == ENOENT ) {
356                         p = strrchr( path, '/' );
357                 }
358 #endif // !GDEF_OS_WINDOWS
359                 if ( p ) {
360                         strncpy( parentbuf, path, sizeof( parentbuf ) );
361                         if ( (int) ( p - path ) < (int) sizeof( parentbuf ) ) {
362                                 parentbuf[p - path] = 0;
363                                 Sys_Printf( "mkdir: %s: creating parent %s first\n", path, parentbuf );
364                                 Q_mkdir( parentbuf );
365                                 continue;
366                         }
367                 }
368                 break;
369         }
370         if ( errno != EEXIST ) {
371                 Error( "mkdir %s: %s",path, strerror( errno ) );
372         }
373 }
374
375 /*
376    ============
377    FileTime
378
379    returns -1 if not present
380    ============
381  */
382 int FileTime( const char *path ){
383         struct  stat buf;
384
385         if ( stat( path,&buf ) == -1 ) {
386                 return -1;
387         }
388
389         return buf.st_mtime;
390 }
391
392
393
394 /*
395    ==============
396    COM_Parse
397
398    Parse a token out of a string
399    ==============
400  */
401 char *COM_Parse( char *data ){
402         int c;
403         int len;
404
405         len = 0;
406         com_token[0] = 0;
407
408         if ( !data ) {
409                 return NULL;
410         }
411
412 // skip whitespace
413 skipwhite:
414         while ( ( c = *data ) <= ' ' )
415         {
416                 if ( c == 0 ) {
417                         com_eof = qtrue;
418                         return NULL;            // end of file;
419                 }
420                 data++;
421         }
422
423 // skip // comments
424         if ( c == '/' && data[1] == '/' ) {
425                 while ( *data && *data != '\n' )
426                         data++;
427                 goto skipwhite;
428         }
429
430
431 // handle quoted strings specially
432         if ( c == '\"' ) {
433                 data++;
434                 do
435                 {
436                         c = *data++;
437                         if ( c == '\"' ) {
438                                 com_token[len] = 0;
439                                 return data;
440                         }
441                         com_token[len] = c;
442                         len++;
443                 } while ( 1 );
444         }
445
446 // parse single characters
447         if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) {
448                 com_token[len] = c;
449                 len++;
450                 com_token[len] = 0;
451                 return data + 1;
452         }
453
454 // parse a regular word
455         do
456         {
457                 com_token[len] = c;
458                 data++;
459                 len++;
460                 c = *data;
461                 if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) {
462                         break;
463                 }
464         } while ( c > 32 );
465
466         com_token[len] = 0;
467         return data;
468 }
469
470 int Q_strncasecmp( const char *s1, const char *s2, int n ){
471         int c1, c2;
472
473         do
474         {
475                 c1 = *s1++;
476                 c2 = *s2++;
477
478                 if ( !n-- ) {
479                         return 0;       // strings are equal until end point
480
481                 }
482                 if ( c1 != c2 ) {
483                         if ( c1 >= 'a' && c1 <= 'z' ) {
484                                 c1 -= ( 'a' - 'A' );
485                         }
486                         if ( c2 >= 'a' && c2 <= 'z' ) {
487                                 c2 -= ( 'a' - 'A' );
488                         }
489                         if ( c1 != c2 ) {
490                                 return -1;      // strings not equal
491                         }
492                 }
493         } while ( c1 );
494
495         return 0;       // strings are equal
496 }
497
498 int Q_stricmp( const char *s1, const char *s2 ){
499         return Q_strncasecmp( s1, s2, 99999 );
500 }
501
502 // NOTE TTimo when switching to Multithread DLL (Release/Debug) in the config
503 //   started getting warnings about that function, prolly a duplicate with the runtime function
504 //   maybe we still need to have it in linux builds
505 /*
506    char *strupr (char *start)
507    {
508     char        *in;
509     in = start;
510     while (*in)
511     {
512    *in = toupper(*in);
513         in++;
514     }
515     return start;
516    }
517  */
518
519 char *strlower( char *start ){
520         char    *in;
521         in = start;
522         while ( *in )
523         {
524                 *in = tolower( *in );
525                 in++;
526         }
527         return start;
528 }
529
530
531 /*
532    =============================================================================
533
534                         MISC FUNCTIONS
535
536    =============================================================================
537  */
538
539
540 /*
541    =================
542    CheckParm
543
544    Checks for the given parameter in the program's command line arguments
545    Returns the argument number (1 to argc-1) or 0 if not present
546    =================
547  */
548 int CheckParm( const char *check ){
549         int i;
550
551         for ( i = 1; i < myargc; i++ )
552         {
553                 if ( !Q_stricmp( check, myargv[i] ) ) {
554                         return i;
555                 }
556         }
557
558         return 0;
559 }
560
561
562
563 /*
564    ================
565    Q_filelength
566    ================
567  */
568 int Q_filelength( FILE *f ){
569         int pos;
570         int end;
571
572         pos = ftell( f );
573         fseek( f, 0, SEEK_END );
574         end = ftell( f );
575         fseek( f, pos, SEEK_SET );
576
577         return end;
578 }
579
580
581 FILE *SafeOpenWrite( const char *filename ){
582         FILE    *f;
583
584         f = fopen( filename, "wb" );
585
586         if ( !f ) {
587                 Error( "Error opening %s: %s",filename,strerror( errno ) );
588         }
589
590         return f;
591 }
592
593 FILE *SafeOpenRead( const char *filename ){
594         FILE    *f;
595
596         f = fopen( filename, "rb" );
597
598         if ( !f ) {
599                 Error( "Error opening %s: %s",filename,strerror( errno ) );
600         }
601
602         return f;
603 }
604
605
606 void SafeRead( FILE *f, void *buffer, int count ){
607         if ( fread( buffer, 1, count, f ) != (size_t)count ) {
608                 Error( "File read failure" );
609         }
610 }
611
612
613 void SafeWrite( FILE *f, const void *buffer, int count ){
614         if ( fwrite( buffer, 1, count, f ) != (size_t)count ) {
615                 Error( "File write failure" );
616         }
617 }
618
619
620 /*
621    ==============
622    FileExists
623    ==============
624  */
625 qboolean    FileExists( const char *filename ){
626         FILE    *f;
627
628         f = fopen( filename, "r" );
629         if ( !f ) {
630                 return qfalse;
631         }
632         fclose( f );
633         return qtrue;
634 }
635
636 /*
637    ==============
638    LoadFile
639    ==============
640  */
641 int    LoadFile( const char *filename, void **bufferptr ){
642         FILE    *f;
643         int length;
644         void    *buffer;
645
646         f = SafeOpenRead( filename );
647         length = Q_filelength( f );
648         buffer = safe_malloc( length + 1 );
649         ( (char *)buffer )[length] = 0;
650         SafeRead( f, buffer, length );
651         fclose( f );
652
653         *bufferptr = buffer;
654         return length;
655 }
656
657
658 /*
659    ==============
660    LoadFileBlock
661    -
662    rounds up memory allocation to 4K boundry
663    -
664    ==============
665  */
666 int    LoadFileBlock( const char *filename, void **bufferptr ){
667         FILE    *f;
668         int length, nBlock, nAllocSize;
669         void    *buffer;
670
671         f = SafeOpenRead( filename );
672         length = Q_filelength( f );
673         nAllocSize = length;
674         nBlock = nAllocSize % MEM_BLOCKSIZE;
675         if ( nBlock > 0 ) {
676                 nAllocSize += MEM_BLOCKSIZE - nBlock;
677         }
678         buffer = safe_malloc( nAllocSize + 1 );
679         memset( buffer, 0, nAllocSize + 1 );
680         SafeRead( f, buffer, length );
681         fclose( f );
682
683         *bufferptr = buffer;
684         return length;
685 }
686
687
688 /*
689    ==============
690    TryLoadFile
691
692    Allows failure
693    ==============
694  */
695 int    TryLoadFile( const char *filename, void **bufferptr ){
696         FILE    *f;
697         int length;
698         void    *buffer;
699
700         *bufferptr = NULL;
701
702         f = fopen( filename, "rb" );
703         if ( !f ) {
704                 return -1;
705         }
706         length = Q_filelength( f );
707         buffer = safe_malloc( length + 1 );
708         ( (char *)buffer )[length] = 0;
709         SafeRead( f, buffer, length );
710         fclose( f );
711
712         *bufferptr = buffer;
713         return length;
714 }
715
716
717 /*
718    ==============
719    SaveFile
720    ==============
721  */
722 void    SaveFile( const char *filename, const void *buffer, int count ){
723         FILE    *f;
724
725         f = SafeOpenWrite( filename );
726         SafeWrite( f, buffer, count );
727         fclose( f );
728 }
729
730
731
732 void DefaultExtension( char *path, const char *extension ){
733         char    *src;
734 //
735 // if path doesnt have a .EXT, append extension
736 // (extension should include the .)
737 //
738         src = path + strlen( path ) - 1;
739
740         while ( *src != '/' && *src != '\\' && src != path )
741         {
742                 if ( *src == '.' ) {
743                         return;                 // it has an extension
744                 }
745                 src--;
746         }
747
748         strcat( path, extension );
749 }
750
751
752 void DefaultPath( char *path, const char *basepath ){
753         char temp[128];
754
755         if ( path[ 0 ] == '/' || path[ 0 ] == '\\' ) {
756                 return;                   // absolute path location
757         }
758         strcpy( temp,path );
759         strcpy( path,basepath );
760         strcat( path,temp );
761 }
762
763
764 void    StripFilename( char *path ){
765         int length;
766
767         length = strlen( path ) - 1;
768         while ( length > 0 && path[length] != '/' && path[ length ] != '\\' )
769                 length--;
770         path[length] = 0;
771 }
772
773 void    StripExtension( char *path ){
774         int length;
775
776         length = strlen( path ) - 1;
777         while ( length > 0 && path[length] != '.' )
778         {
779                 length--;
780                 if ( path[length] == '/' || path[ length ] == '\\' ) {
781                         return;     // no extension
782                 }
783         }
784         if ( length ) {
785                 path[length] = 0;
786         }
787 }
788
789
790 /*
791    ====================
792    Extract file parts
793    ====================
794  */
795 // FIXME: should include the slash, otherwise
796 // backing to an empty path will be wrong when appending a slash
797 void ExtractFilePath( const char *path, char *dest ){
798         const char    *src;
799
800         src = path + strlen( path ) - 1;
801
802 //
803 // back up until a \ or the start
804 //
805         while ( src != path && *( src - 1 ) != '\\' && *( src - 1 ) != '/' )
806                 src--;
807
808         memcpy( dest, path, src - path );
809         dest[src - path] = 0;
810 }
811
812 void ExtractFileBase( const char *path, char *dest ){
813         const char    *src;
814
815         src = path + strlen( path ) - 1;
816
817 //
818 // back up until a \ or the start
819 //
820         while ( src != path && *( src - 1 ) != '/' && *( src - 1 ) != '\\' )
821                 src--;
822
823         while ( *src && *src != '.' )
824         {
825                 *dest++ = *src++;
826         }
827         *dest = 0;
828 }
829
830 void ExtractFileExtension( const char *path, char *dest ){
831         const char    *src;
832
833         src = path + strlen( path ) - 1;
834
835 //
836 // back up until a . or the start
837 //
838         while ( src != path && *( src - 1 ) != '.' )
839                 src--;
840         if ( src == path ) {
841                 *dest = 0;  // no extension
842                 return;
843         }
844
845         strcpy( dest,src );
846 }
847
848
849 /*
850    ==============
851    ParseNum / ParseHex
852    ==============
853  */
854 int ParseHex( const char *hex ){
855         const char    *str;
856         int num;
857
858         num = 0;
859         str = hex;
860
861         while ( *str )
862         {
863                 num <<= 4;
864                 if ( *str >= '0' && *str <= '9' ) {
865                         num += *str - '0';
866                 }
867                 else if ( *str >= 'a' && *str <= 'f' ) {
868                         num += 10 + *str - 'a';
869                 }
870                 else if ( *str >= 'A' && *str <= 'F' ) {
871                         num += 10 + *str - 'A';
872                 }
873                 else{
874                         Error( "Bad hex number: %s",hex );
875                 }
876                 str++;
877         }
878
879         return num;
880 }
881
882
883 int ParseNum( const char *str ){
884         if ( str[0] == '$' ) {
885                 return ParseHex( str + 1 );
886         }
887         if ( str[0] == '0' && str[1] == 'x' ) {
888                 return ParseHex( str + 2 );
889         }
890         return atol( str );
891 }
892
893
894
895 /*
896    ============================================================================
897
898                     BYTE ORDER FUNCTIONS
899
900    ============================================================================
901  */
902
903 #if GDEF_ARCH_ENDIAN_BIG
904
905 short   LittleShort( short l ){
906         byte b1,b2;
907
908         b1 = l & 255;
909         b2 = ( l >> 8 ) & 255;
910
911         return ( b1 << 8 ) + b2;
912 }
913
914 short   BigShort( short l ){
915         return l;
916 }
917
918
919 int    LittleLong( int l ){
920         byte b1,b2,b3,b4;
921
922         b1 = l & 255;
923         b2 = ( l >> 8 ) & 255;
924         b3 = ( l >> 16 ) & 255;
925         b4 = ( l >> 24 ) & 255;
926
927         return ( (int)b1 << 24 ) + ( (int)b2 << 16 ) + ( (int)b3 << 8 ) + b4;
928 }
929
930 int    BigLong( int l ){
931         return l;
932 }
933
934
935 float   LittleFloat( float l ){
936         union {byte b[4]; float f; } in, out;
937
938         in.f = l;
939         out.b[0] = in.b[3];
940         out.b[1] = in.b[2];
941         out.b[2] = in.b[1];
942         out.b[3] = in.b[0];
943
944         return out.f;
945 }
946
947 float   BigFloat( float l ){
948         return l;
949 }
950
951 #else // !GDEF_ARCH_ENDIAN_BIG
952
953 short   BigShort( short l ){
954         byte b1,b2;
955
956         b1 = l & 255;
957         b2 = ( l >> 8 ) & 255;
958
959         return ( b1 << 8 ) + b2;
960 }
961
962 short   LittleShort( short l ){
963         return l;
964 }
965
966
967 int    BigLong( int l ){
968         byte b1,b2,b3,b4;
969
970         b1 = l & 255;
971         b2 = ( l >> 8 ) & 255;
972         b3 = ( l >> 16 ) & 255;
973         b4 = ( l >> 24 ) & 255;
974
975         return ( (int)b1 << 24 ) + ( (int)b2 << 16 ) + ( (int)b3 << 8 ) + b4;
976 }
977
978 int    LittleLong( int l ){
979         return l;
980 }
981
982 float   BigFloat( float l ){
983         union {byte b[4]; float f; } in, out;
984
985         in.f = l;
986         out.b[0] = in.b[3];
987         out.b[1] = in.b[2];
988         out.b[2] = in.b[1];
989         out.b[3] = in.b[0];
990
991         return out.f;
992 }
993
994 float   LittleFloat( float l ){
995         return l;
996 }
997
998 #endif // !GDEF_ARCH_ENDIAN_BIG
999
1000
1001 //=======================================================
1002
1003
1004 // FIXME: byte swap?
1005
1006 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
1007 // and the initial and final xor values shown below...  in other words, the
1008 // CCITT standard CRC used by XMODEM
1009
1010 #define CRC_INIT_VALUE  0xffff
1011 #define CRC_XOR_VALUE   0x0000
1012
1013 static unsigned short crctable[256] =
1014 {
1015         0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
1016         0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
1017         0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
1018         0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
1019         0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
1020         0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
1021         0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
1022         0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
1023         0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
1024         0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
1025         0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
1026         0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
1027         0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
1028         0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
1029         0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
1030         0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
1031         0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
1032         0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
1033         0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
1034         0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
1035         0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
1036         0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
1037         0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
1038         0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
1039         0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
1040         0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
1041         0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
1042         0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
1043         0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
1044         0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
1045         0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
1046         0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
1047 };
1048
1049 void CRC_Init( unsigned short *crcvalue ){
1050         *crcvalue = CRC_INIT_VALUE;
1051 }
1052
1053 void CRC_ProcessByte( unsigned short *crcvalue, byte data ){
1054         *crcvalue = ( *crcvalue << 8 ) ^ crctable[( *crcvalue >> 8 ) ^ data];
1055 }
1056
1057 unsigned short CRC_Value( unsigned short crcvalue ){
1058         return crcvalue ^ CRC_XOR_VALUE;
1059 }
1060 //=============================================================================
1061
1062 /*
1063    ============
1064    CreatePath
1065    ============
1066  */
1067 void    CreatePath( const char *path ){
1068         const char  *ofs;
1069         char c;
1070         char dir[1024];
1071
1072 #if GDEF_OS_WINDOWS
1073         int olddrive = -1;
1074
1075         if ( path[1] == ':' ) {
1076                 olddrive = _getdrive();
1077                 _chdrive( toupper( path[0] ) - 'A' + 1 );
1078         }
1079 #endif // !GDEF_OS_WINDOWS
1080
1081         if ( path[1] == ':' ) {
1082                 path += 2;
1083         }
1084
1085         for ( ofs = path + 1 ; *ofs ; ofs++ )
1086         {
1087                 c = *ofs;
1088                 if ( c == '/' || c == '\\' ) { // create the directory
1089                         memcpy( dir, path, ofs - path );
1090                         dir[ ofs - path ] = 0;
1091                         Q_mkdir( dir );
1092                 }
1093         }
1094
1095 #if GDEF_OS_WINDOWS
1096         if ( olddrive != -1 ) {
1097                 _chdrive( olddrive );
1098         }
1099 #endif // !>GDEF_OS_WINDOWS
1100 }
1101
1102
1103 /*
1104    ============
1105    QCopyFile
1106
1107    Used to archive source files
1108    ============
1109  */
1110 void QCopyFile( const char *from, const char *to ){
1111         void    *buffer;
1112         int length;
1113
1114         length = LoadFile( from, &buffer );
1115         CreatePath( to );
1116         SaveFile( to, buffer, length );
1117         free( buffer );
1118 }
1119
1120 void Sys_Sleep( int n ){
1121 #if GDEF_OS_WINDOWS
1122         Sleep( n );
1123 #else // !GDEF_OS_WINDOWS
1124         usleep( n * 1000 );
1125 #endif // !GDEF_OS_WINDOWS
1126 }