]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/common/cmdlib.c
netradiant: strip 16-bit png to 8-bit, fix #153
[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 char *strlower( char *start ){
503         char    *in;
504         in = start;
505         while ( *in )
506         {
507                 *in = tolower( *in );
508                 in++;
509         }
510         return start;
511 }
512
513
514 /*
515    =============================================================================
516
517                         MISC FUNCTIONS
518
519    =============================================================================
520  */
521
522
523 /*
524    =================
525    CheckParm
526
527    Checks for the given parameter in the program's command line arguments
528    Returns the argument number (1 to argc-1) or 0 if not present
529    =================
530  */
531 int CheckParm( const char *check ){
532         int i;
533
534         for ( i = 1; i < myargc; i++ )
535         {
536                 if ( !Q_stricmp( check, myargv[i] ) ) {
537                         return i;
538                 }
539         }
540
541         return 0;
542 }
543
544
545
546 /*
547    ================
548    Q_filelength
549    ================
550  */
551 int Q_filelength( FILE *f ){
552         int pos;
553         int end;
554
555         pos = ftell( f );
556         fseek( f, 0, SEEK_END );
557         end = ftell( f );
558         fseek( f, pos, SEEK_SET );
559
560         return end;
561 }
562
563
564 FILE *SafeOpenWrite( const char *filename ){
565         FILE    *f;
566
567         f = fopen( filename, "wb" );
568
569         if ( !f ) {
570                 Error( "Error opening %s: %s",filename,strerror( errno ) );
571         }
572
573         return f;
574 }
575
576 FILE *SafeOpenRead( const char *filename ){
577         FILE    *f;
578
579         f = fopen( filename, "rb" );
580
581         if ( !f ) {
582                 Error( "Error opening %s: %s",filename,strerror( errno ) );
583         }
584
585         return f;
586 }
587
588
589 void SafeRead( FILE *f, void *buffer, int count ){
590         if ( fread( buffer, 1, count, f ) != (size_t)count ) {
591                 Error( "File read failure" );
592         }
593 }
594
595
596 void SafeWrite( FILE *f, const void *buffer, int count ){
597         if ( fwrite( buffer, 1, count, f ) != (size_t)count ) {
598                 Error( "File write failure" );
599         }
600 }
601
602
603 /*
604    ==============
605    FileExists
606    ==============
607  */
608 qboolean    FileExists( const char *filename ){
609         FILE    *f;
610
611         f = fopen( filename, "r" );
612         if ( !f ) {
613                 return qfalse;
614         }
615         fclose( f );
616         return qtrue;
617 }
618
619 /*
620    ==============
621    LoadFile
622    ==============
623  */
624 int    LoadFile( const char *filename, void **bufferptr ){
625         FILE    *f;
626         int length;
627         void    *buffer;
628
629         f = SafeOpenRead( filename );
630         length = Q_filelength( f );
631         buffer = safe_malloc( length + 1 );
632         ( (char *)buffer )[length] = 0;
633         SafeRead( f, buffer, length );
634         fclose( f );
635
636         *bufferptr = buffer;
637         return length;
638 }
639
640
641 /*
642    ==============
643    LoadFileBlock
644    -
645    rounds up memory allocation to 4K boundry
646    -
647    ==============
648  */
649 int    LoadFileBlock( const char *filename, void **bufferptr ){
650         FILE    *f;
651         int length, nBlock, nAllocSize;
652         void    *buffer;
653
654         f = SafeOpenRead( filename );
655         length = Q_filelength( f );
656         nAllocSize = length;
657         nBlock = nAllocSize % MEM_BLOCKSIZE;
658         if ( nBlock > 0 ) {
659                 nAllocSize += MEM_BLOCKSIZE - nBlock;
660         }
661         buffer = safe_malloc0( nAllocSize + 1 );
662         SafeRead( f, buffer, length );
663         fclose( f );
664
665         *bufferptr = buffer;
666         return length;
667 }
668
669
670 /*
671    ==============
672    TryLoadFile
673
674    Allows failure
675    ==============
676  */
677 int    TryLoadFile( const char *filename, void **bufferptr ){
678         FILE    *f;
679         int length;
680         void    *buffer;
681
682         *bufferptr = NULL;
683
684         f = fopen( filename, "rb" );
685         if ( !f ) {
686                 return -1;
687         }
688         length = Q_filelength( f );
689         buffer = safe_malloc( length + 1 );
690         ( (char *)buffer )[length] = 0;
691         SafeRead( f, buffer, length );
692         fclose( f );
693
694         *bufferptr = buffer;
695         return length;
696 }
697
698
699 /*
700    ==============
701    SaveFile
702    ==============
703  */
704 void    SaveFile( const char *filename, const void *buffer, int count ){
705         FILE    *f;
706
707         f = SafeOpenWrite( filename );
708         SafeWrite( f, buffer, count );
709         fclose( f );
710 }
711
712
713
714 void DefaultExtension( char *path, const char *extension ){
715         char    *src;
716 //
717 // if path doesnt have a .EXT, append extension
718 // (extension should include the .)
719 //
720         src = path + strlen( path ) - 1;
721
722         while ( *src != '/' && *src != '\\' && src != path )
723         {
724                 if ( *src == '.' ) {
725                         return;                 // it has an extension
726                 }
727                 src--;
728         }
729
730         strcat( path, extension );
731 }
732
733
734 void DefaultPath( char *path, const char *basepath ){
735         char temp[128];
736
737         if ( path[ 0 ] == '/' || path[ 0 ] == '\\' ) {
738                 return;                   // absolute path location
739         }
740         strcpy( temp,path );
741         strcpy( path,basepath );
742         strcat( path,temp );
743 }
744
745
746 void    StripFilename( char *path ){
747         int length;
748
749         length = strlen( path ) - 1;
750         while ( length > 0 && path[length] != '/' && path[ length ] != '\\' )
751                 length--;
752         path[length] = 0;
753 }
754
755 void    StripExtension( char *path ){
756         int length;
757
758         length = strlen( path ) - 1;
759         while ( length > 0 && path[length] != '.' )
760         {
761                 length--;
762                 if ( path[length] == '/' || path[ length ] == '\\' ) {
763                         return;     // no extension
764                 }
765         }
766         if ( length ) {
767                 path[length] = 0;
768         }
769 }
770
771
772 /*
773    ====================
774    Extract file parts
775    ====================
776  */
777 // FIXME: should include the slash, otherwise
778 // backing to an empty path will be wrong when appending a slash
779 void ExtractFilePath( const char *path, char *dest ){
780         const char    *src;
781
782         src = path + strlen( path ) - 1;
783
784 //
785 // back up until a \ or the start
786 //
787         while ( src != path && *( src - 1 ) != '\\' && *( src - 1 ) != '/' )
788                 src--;
789
790         memcpy( dest, path, src - path );
791         dest[src - path] = 0;
792 }
793
794 void ExtractFileBase( const char *path, char *dest ){
795         const char    *src;
796
797         src = path + strlen( path ) - 1;
798
799 //
800 // back up until a \ or the start
801 //
802         while ( src != path && *( src - 1 ) != '/' && *( src - 1 ) != '\\' )
803                 src--;
804
805         while ( *src && *src != '.' )
806         {
807                 *dest++ = *src++;
808         }
809         *dest = 0;
810 }
811
812 void ExtractFileExtension( 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 ) != '.' )
821                 src--;
822         if ( src == path ) {
823                 *dest = 0;  // no extension
824                 return;
825         }
826
827         strcpy( dest,src );
828 }
829
830
831 /*
832    ==============
833    ParseNum / ParseHex
834    ==============
835  */
836 int ParseHex( const char *hex ){
837         const char    *str;
838         int num;
839
840         num = 0;
841         str = hex;
842
843         while ( *str )
844         {
845                 num <<= 4;
846                 if ( *str >= '0' && *str <= '9' ) {
847                         num += *str - '0';
848                 }
849                 else if ( *str >= 'a' && *str <= 'f' ) {
850                         num += 10 + *str - 'a';
851                 }
852                 else if ( *str >= 'A' && *str <= 'F' ) {
853                         num += 10 + *str - 'A';
854                 }
855                 else{
856                         Error( "Bad hex number: %s",hex );
857                 }
858                 str++;
859         }
860
861         return num;
862 }
863
864
865 int ParseNum( const char *str ){
866         if ( str[0] == '$' ) {
867                 return ParseHex( str + 1 );
868         }
869         if ( str[0] == '0' && str[1] == 'x' ) {
870                 return ParseHex( str + 2 );
871         }
872         return atol( str );
873 }
874
875
876
877 /*
878    ============================================================================
879
880                     BYTE ORDER FUNCTIONS
881
882    ============================================================================
883  */
884
885 #if GDEF_ARCH_ENDIAN_BIG
886
887 short   LittleShort( short l ){
888         byte b1,b2;
889
890         b1 = l & 255;
891         b2 = ( l >> 8 ) & 255;
892
893         return ( b1 << 8 ) + b2;
894 }
895
896 short   BigShort( short l ){
897         return l;
898 }
899
900
901 int    LittleLong( int l ){
902         byte b1,b2,b3,b4;
903
904         b1 = l & 255;
905         b2 = ( l >> 8 ) & 255;
906         b3 = ( l >> 16 ) & 255;
907         b4 = ( l >> 24 ) & 255;
908
909         return ( (int)b1 << 24 ) + ( (int)b2 << 16 ) + ( (int)b3 << 8 ) + b4;
910 }
911
912 int    BigLong( int l ){
913         return l;
914 }
915
916
917 float   LittleFloat( float l ){
918         union {byte b[4]; float f; } in, out;
919
920         in.f = l;
921         out.b[0] = in.b[3];
922         out.b[1] = in.b[2];
923         out.b[2] = in.b[1];
924         out.b[3] = in.b[0];
925
926         return out.f;
927 }
928
929 float   BigFloat( float l ){
930         return l;
931 }
932
933 #else // !GDEF_ARCH_ENDIAN_BIG
934
935 short   BigShort( short l ){
936         byte b1,b2;
937
938         b1 = l & 255;
939         b2 = ( l >> 8 ) & 255;
940
941         return ( b1 << 8 ) + b2;
942 }
943
944 short   LittleShort( short l ){
945         return l;
946 }
947
948
949 int    BigLong( int l ){
950         byte b1,b2,b3,b4;
951
952         b1 = l & 255;
953         b2 = ( l >> 8 ) & 255;
954         b3 = ( l >> 16 ) & 255;
955         b4 = ( l >> 24 ) & 255;
956
957         return ( (int)b1 << 24 ) + ( (int)b2 << 16 ) + ( (int)b3 << 8 ) + b4;
958 }
959
960 int    LittleLong( int l ){
961         return l;
962 }
963
964 float   BigFloat( float l ){
965         union {byte b[4]; float f; } in, out;
966
967         in.f = l;
968         out.b[0] = in.b[3];
969         out.b[1] = in.b[2];
970         out.b[2] = in.b[1];
971         out.b[3] = in.b[0];
972
973         return out.f;
974 }
975
976 float   LittleFloat( float l ){
977         return l;
978 }
979
980 #endif // !GDEF_ARCH_ENDIAN_BIG
981
982
983 //=======================================================
984
985
986 // FIXME: byte swap?
987
988 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
989 // and the initial and final xor values shown below...  in other words, the
990 // CCITT standard CRC used by XMODEM
991
992 #define CRC_INIT_VALUE  0xffff
993 #define CRC_XOR_VALUE   0x0000
994
995 static unsigned short crctable[256] =
996 {
997         0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
998         0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
999         0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
1000         0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
1001         0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
1002         0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
1003         0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
1004         0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
1005         0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
1006         0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
1007         0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
1008         0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
1009         0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
1010         0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
1011         0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
1012         0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
1013         0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
1014         0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
1015         0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
1016         0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
1017         0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
1018         0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
1019         0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
1020         0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
1021         0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
1022         0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
1023         0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
1024         0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
1025         0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
1026         0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
1027         0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
1028         0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
1029 };
1030
1031 void CRC_Init( unsigned short *crcvalue ){
1032         *crcvalue = CRC_INIT_VALUE;
1033 }
1034
1035 void CRC_ProcessByte( unsigned short *crcvalue, byte data ){
1036         *crcvalue = ( *crcvalue << 8 ) ^ crctable[( *crcvalue >> 8 ) ^ data];
1037 }
1038
1039 unsigned short CRC_Value( unsigned short crcvalue ){
1040         return crcvalue ^ CRC_XOR_VALUE;
1041 }
1042 //=============================================================================
1043
1044 /*
1045    ============
1046    CreatePath
1047    ============
1048  */
1049 void    CreatePath( const char *path ){
1050         const char  *ofs;
1051         char c;
1052         char dir[1024];
1053
1054 #if GDEF_OS_WINDOWS
1055         int olddrive = -1;
1056
1057         if ( path[1] == ':' ) {
1058                 olddrive = _getdrive();
1059                 _chdrive( toupper( path[0] ) - 'A' + 1 );
1060         }
1061 #endif // !GDEF_OS_WINDOWS
1062
1063         if ( path[1] == ':' ) {
1064                 path += 2;
1065         }
1066
1067         for ( ofs = path + 1 ; *ofs ; ofs++ )
1068         {
1069                 c = *ofs;
1070                 if ( c == '/' || c == '\\' ) { // create the directory
1071                         memcpy( dir, path, ofs - path );
1072                         dir[ ofs - path ] = 0;
1073                         Q_mkdir( dir );
1074                 }
1075         }
1076
1077 #if GDEF_OS_WINDOWS
1078         if ( olddrive != -1 ) {
1079                 _chdrive( olddrive );
1080         }
1081 #endif // !>GDEF_OS_WINDOWS
1082 }
1083
1084
1085 /*
1086    ============
1087    QCopyFile
1088
1089    Used to archive source files
1090    ============
1091  */
1092 void QCopyFile( const char *from, const char *to ){
1093         void    *buffer;
1094         int length;
1095
1096         length = LoadFile( from, &buffer );
1097         CreatePath( to );
1098         SaveFile( to, buffer, length );
1099         free( buffer );
1100 }
1101
1102 void Sys_Sleep( int n ){
1103 #if GDEF_OS_WINDOWS
1104         Sleep( n );
1105 #else // !GDEF_OS_WINDOWS
1106         usleep( n * 1000 );
1107 #endif // !GDEF_OS_WINDOWS
1108 }