]> git.xonotic.org Git - xonotic/netradiant.git/blob - libs/picomodel/picointernal.c
picomodel: white default color of fm, md2 (was one white and rest black)
[xonotic/netradiant.git] / libs / picomodel / picointernal.c
1 /* -----------------------------------------------------------------------------
2
3    PicoModel Library
4
5    Copyright (c) 2002, Randy Reddig & seaw0lf
6    All rights reserved.
7
8    Redistribution and use in source and binary forms, with or without modification,
9    are permitted provided that the following conditions are met:
10
11    Redistributions of source code must retain the above copyright notice, this list
12    of conditions and the following disclaimer.
13
14    Redistributions in binary form must reproduce the above copyright notice, this
15    list of conditions and the following disclaimer in the documentation and/or
16    other materials provided with the distribution.
17
18    Neither the names of the copyright holders nor the names of its contributors may
19    be used to endorse or promote products derived from this software without
20    specific prior written permission.
21
22    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
26    ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29    ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33    ----------------------------------------------------------------------------- */
34
35 /* todo:
36  * - fix p->curLine for parser routines. increased twice
37  */
38
39 /* dependencies */
40 #include <string.h>
41 #include "picointernal.h"
42 #include "globaldefs.h"
43
44
45
46 /* function pointers */
47 void *( *_pico_ptr_malloc    )( size_t ) = malloc;
48 void ( *_pico_ptr_free      )( void* ) = free;
49 void ( *_pico_ptr_load_file )( const char*, unsigned char**, int* ) = NULL;
50 void ( *_pico_ptr_free_file )( void* ) = NULL;
51 void ( *_pico_ptr_print     )( int, const char* ) = NULL;
52
53 typedef union
54 {
55         float f;
56         char c[4];
57 }
58 floatSwapUnion;
59
60 /* _pico_alloc:
61  *  kludged memory allocation wrapper
62  */
63 void *_pico_alloc( size_t size ){
64         void *ptr;
65
66         /* some sanity checks */
67         if ( size == 0 ) {
68                 return NULL;
69         }
70         if ( _pico_ptr_malloc == NULL ) {
71                 return NULL;
72         }
73
74         /* allocate memory */
75         ptr = _pico_ptr_malloc( size );
76         if ( ptr == NULL ) {
77                 return NULL;
78         }
79
80         /* zero out allocated memory */
81         memset( ptr,0,size );
82
83         /* return pointer to allocated memory */
84         return ptr;
85 }
86
87 /* _pico_calloc:
88  *  _pico_calloc wrapper
89  */
90 void *_pico_calloc( size_t num, size_t size ){
91         void *ptr;
92
93         /* some sanity checks */
94         if ( num == 0 || size == 0 ) {
95                 return NULL;
96         }
97         if ( _pico_ptr_malloc == NULL ) {
98                 return NULL;
99         }
100
101         /* allocate memory */
102         ptr = _pico_ptr_malloc( num * size );
103         if ( ptr == NULL ) {
104                 return NULL;
105         }
106
107         /* zero out allocated memory */
108         memset( ptr,0,num * size );
109
110         /* return pointer to allocated memory */
111         return ptr;
112 }
113
114 /* _pico_realloc:
115  *  memory reallocation wrapper (note: only grows,
116  *  but never shrinks or frees)
117  */
118 void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize ){
119         void *ptr2;
120
121         /* sanity checks */
122         if ( ptr == NULL ) {
123                 return NULL;
124         }
125         if ( newSize < oldSize ) {
126                 return *ptr;
127         }
128         if ( _pico_ptr_malloc == NULL ) {
129                 return NULL;
130         }
131
132         /* allocate new pointer */
133         ptr2 = _pico_alloc( newSize );
134         if ( ptr2 == NULL ) {
135                 return NULL;
136         }
137
138         /* copy */
139         if ( *ptr != NULL ) {
140                 memcpy( ptr2, *ptr, oldSize );
141                 _pico_free( *ptr );
142         }
143
144         /* fix up and return */
145         *ptr = ptr2;
146         return *ptr;
147 }
148
149 /* _pico_clone_alloc:
150  *  handy function for quick string allocation/copy. it clones
151  *  the given string and returns a pointer to the new allocated
152  *  clone (which must be freed by caller of course) or returns
153  *  NULL on memory alloc or param errors. if 'size' is -1 the
154  *  length of the input string is used, otherwise 'size' is used
155  *  as custom clone size (the string is cropped to fit into mem
156  *  if needed). -sea
157  */
158 char *_pico_clone_alloc( const char *str ){
159         char* cloned;
160
161         /* sanity check */
162         if ( str == NULL ) {
163                 return NULL;
164         }
165
166         /* allocate memory */
167         cloned = _pico_alloc( strlen( str ) + 1 );
168         if ( cloned == NULL ) {
169                 return NULL;
170         }
171
172         /* copy input string to cloned string */
173         strcpy( cloned, str );
174
175         /* return ptr to cloned string */
176         return cloned;
177 }
178
179 /* _pico_free:
180  * wrapper around the free function pointer
181  */
182 void _pico_free( void *ptr ){
183         /* sanity checks */
184         if ( ptr == NULL ) {
185                 return;
186         }
187         if ( _pico_ptr_free == NULL ) {
188                 return;
189         }
190
191         /* free the allocated memory */
192         _pico_ptr_free( ptr );
193 }
194
195 /* _pico_load_file:
196  * wrapper around the loadfile function pointer
197  */
198 void _pico_load_file( const char *name, unsigned char **buffer, int *bufSize ){
199         /* sanity checks */
200         if ( name == NULL ) {
201                 *bufSize = -1;
202                 return;
203         }
204         if ( _pico_ptr_load_file == NULL ) {
205                 *bufSize = -1;
206                 return;
207         }
208         /* do the actual call to read in the file; */
209         /* BUFFER IS ALLOCATED BY THE EXTERNAL LOADFILE FUNC */
210         _pico_ptr_load_file( name,buffer,bufSize );
211 }
212
213 /* _pico_free_file:
214  * wrapper around the file free function pointer
215  */
216 void _pico_free_file( void *buffer ){
217         /* sanity checks */
218         if ( buffer == NULL ) {
219                 return;
220         }
221
222         /* use default free */
223         if ( _pico_ptr_free_file == NULL ) {
224                 free( buffer );
225                 return;
226         }
227         /* free the allocated file */
228         _pico_ptr_free_file( buffer );
229 }
230
231 /* _pico_printf:
232  * wrapper around the print function pointer -sea
233  */
234 void _pico_printf( int level, const char *format, ... ){
235         char str[4096];
236         va_list argptr;
237
238         /* sanity checks */
239         if ( format == NULL ) {
240                 return;
241         }
242         if ( _pico_ptr_print == NULL ) {
243                 return;
244         }
245
246         /* format string */
247         va_start( argptr,format );
248         vsprintf( str,format,argptr );
249         va_end( argptr );
250
251         /* remove linefeeds */
252         if ( str[ strlen( str ) - 1 ] == '\n' ) {
253                 str[ strlen( str ) - 1 ] = '\0';
254         }
255
256         /* do the actual call */
257         _pico_ptr_print( level,str );
258 }
259
260 /* _pico_first_token:
261  * trims everything after the first whitespace-delimited token
262  */
263
264 void _pico_first_token( char *str ){
265         if ( !str || !*str ) {
266                 return;
267         }
268         while ( *str && !isspace( *str ) )
269                 str++;
270         *str = '\0';
271 }
272
273 /* _pico_strltrim:
274  * left trims the given string -sea
275  */
276 char *_pico_strltrim( char *str ){
277         char *str1 = str, *str2 = str;
278
279         while ( isspace( *str2 ) ) str2++;
280         if ( str2 != str ) {
281                 while ( *str2 != '\0' ) /* fix: ydnar */
282                         *str1++ = *str2++;
283         }
284         return str;
285 }
286
287 /* _pico_strrtrim:
288  * right trims the given string -sea
289  */
290 char *_pico_strrtrim( char *str ){
291         if ( str && *str ) {
292                 char *str1 = str;
293                 int allspace = 1;
294
295                 while ( *str1 )
296                 {
297                         if ( allspace && !isspace( *str1 ) ) {
298                                 allspace = 0;
299                         }
300                         str1++;
301                 }
302                 if ( allspace ) {
303                         *str = '\0';
304                 }
305                 else {
306                         str1--;
307                         while ( ( isspace( *str1 ) ) && ( str1 >= str ) )
308                                 *str1-- = '\0';
309                 }
310         }
311         return str;
312 }
313
314 /* _pico_strlwr:
315  *  pico internal string-to-lower routine.
316  */
317 char *_pico_strlwr( char *str ){
318         char *cp;
319         for ( cp = str; *cp; ++cp )
320         {
321                 if ( 'A' <= *cp && *cp <= 'Z' ) {
322                         *cp += ( 'a' - 'A' );
323                 }
324         }
325         return str;
326 }
327
328 /* _pico_strchcount:
329  *  counts how often the given char appears in str. -sea
330  */
331 int _pico_strchcount( char *str, int ch ){
332         int count = 0;
333         while ( *str++ ) if ( *str == ch ) {
334                         count++;
335                 }
336         return count;
337 }
338
339 void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs ){
340         int i;
341         for ( i = 0; i < 3; i++ )
342         {
343                 mins[i] = +999999;
344                 maxs[i] = -999999;
345         }
346 }
347
348 void _pico_expand_bounds( picoVec3_t p, picoVec3_t mins, picoVec3_t maxs ){
349         int i;
350         for ( i = 0; i < 3; i++ )
351         {
352                 float value = p[i];
353                 if ( value < mins[i] ) {
354                         mins[i] = value;
355                 }
356                 if ( value > maxs[i] ) {
357                         maxs[i] = value;
358                 }
359         }
360 }
361
362 void _pico_zero_vec( picoVec3_t vec ){
363         vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = 0;
364 }
365
366 void _pico_zero_vec2( picoVec2_t vec ){
367         vec[ 0 ] = vec[ 1 ] = 0;
368 }
369
370 void _pico_zero_vec4( picoVec4_t vec ){
371         vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = vec[ 3 ] = 0;
372 }
373
374 void _pico_set_vec( picoVec3_t v, float a, float b, float c ){
375         v[ 0 ] = a;
376         v[ 1 ] = b;
377         v[ 2 ] = c;
378 }
379
380 void _pico_set_vec4( picoVec4_t v, float a, float b, float c, float d ){
381         v[ 0 ] = a;
382         v[ 1 ] = b;
383         v[ 2 ] = c;
384         v[ 3 ] = d;
385 }
386
387 void _pico_copy_vec( picoVec3_t src, picoVec3_t dest ){
388         dest[ 0 ] = src[ 0 ];
389         dest[ 1 ] = src[ 1 ];
390         dest[ 2 ] = src[ 2 ];
391 }
392
393 void _pico_copy_vec2( picoVec2_t src, picoVec2_t dest ){
394         dest[ 0 ] = src[ 0 ];
395         dest[ 1 ] = src[ 1 ];
396 }
397
398 void _pico_copy_vec4( picoVec4_t src, picoVec4_t dest ){
399         dest[ 0 ] = src[ 0 ];
400         dest[ 1 ] = src[ 1 ];
401         dest[ 2 ] = src[ 2 ];
402         dest[ 3 ] = src[ 3 ];
403 }
404
405 /* ydnar */
406 picoVec_t _pico_normalize_vec( picoVec3_t vec ){
407         double len, ilen;
408
409         len = sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] + vec[ 2 ] * vec[ 2 ] );
410         if ( len == 0.0 ) {
411                 return 0.0;
412         }
413         ilen = 1.0 / len;
414         vec[ 0 ] *= (picoVec_t) ilen;
415         vec[ 1 ] *= (picoVec_t) ilen;
416         vec[ 2 ] *= (picoVec_t) ilen;
417         return (picoVec_t) len;
418 }
419
420 void _pico_add_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ){
421         dest[ 0 ] = a[ 0 ] + b[ 0 ];
422         dest[ 1 ] = a[ 1 ] + b[ 1 ];
423         dest[ 2 ] = a[ 2 ] + b[ 2 ];
424 }
425
426 void _pico_subtract_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ){
427         dest[ 0 ] = a[ 0 ] - b[ 0 ];
428         dest[ 1 ] = a[ 1 ] - b[ 1 ];
429         dest[ 2 ] = a[ 2 ] - b[ 2 ];
430 }
431
432 void _pico_scale_vec( picoVec3_t v, float scale, picoVec3_t dest ){
433         dest[ 0 ] = v[ 0 ] * scale;
434         dest[ 1 ] = v[ 1 ] * scale;
435         dest[ 2 ] = v[ 2 ] * scale;
436 }
437
438 void _pico_scale_vec4( picoVec4_t v, float scale, picoVec4_t dest ){
439         dest[ 0 ] = v[ 0 ] * scale;
440         dest[ 1 ] = v[ 1 ] * scale;
441         dest[ 2 ] = v[ 2 ] * scale;
442         dest[ 3 ] = v[ 3 ] * scale;
443 }
444
445 picoVec_t _pico_dot_vec( picoVec3_t a, picoVec3_t b ){
446         return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ];
447 }
448
449 void _pico_cross_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ){
450         dest[ 0 ] = a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ];
451         dest[ 1 ] = a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ];
452         dest[ 2 ] = a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ];
453 }
454
455 picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVec3_t c ){
456         picoVec3_t ba, ca;
457
458         _pico_subtract_vec( b, a, ba );
459         _pico_subtract_vec( c, a, ca );
460         _pico_cross_vec( ca, ba, plane );
461         plane[ 3 ] = _pico_dot_vec( a, plane );
462         return _pico_normalize_vec( plane );
463 }
464
465 const picoColor_t picoColor_white = { 255, 255, 255, 255 };
466
467 /* separate from _pico_set_vec4 */
468 void _pico_set_color( picoColor_t c, int r, int g, int b, int a ){
469         c[ 0 ] = r;
470         c[ 1 ] = g;
471         c[ 2 ] = b;
472         c[ 3 ] = a;
473 }
474
475 void _pico_copy_color( const picoColor_t src, picoColor_t dest ){
476         dest[ 0 ] = src[ 0 ];
477         dest[ 1 ] = src[ 1 ];
478         dest[ 2 ] = src[ 2 ];
479         dest[ 3 ] = src[ 3 ];
480 }
481
482 #if GDEF_ARCH_ENDIAN_BIG
483
484 int   _pico_big_long( int src ) { return src; }
485 short _pico_big_short( short src ) { return src; }
486 float _pico_big_float( float src ) { return src; }
487
488 int _pico_little_long( int src ){
489         return ( ( src & 0xFF000000 ) >> 24 ) |
490                    ( ( src & 0x00FF0000 ) >> 8 ) |
491                    ( ( src & 0x0000FF00 ) << 8 ) |
492                    ( ( src & 0x000000FF ) << 24 );
493 }
494
495 short _pico_little_short( short src ){
496         return ( ( src & 0xFF00 ) >> 8 ) |
497                    ( ( src & 0x00FF ) << 8 );
498 }
499
500 float _pico_little_float( float src ){
501         floatSwapUnion in,out;
502         in.f = src;
503         out.c[ 0 ] = in.c[ 3 ];
504         out.c[ 1 ] = in.c[ 2 ];
505         out.c[ 2 ] = in.c[ 1 ];
506         out.c[ 3 ] = in.c[ 0 ];
507         return out.f;
508 }
509 #else /*__BIG_ENDIAN__*/
510
511 int   _pico_little_long( int src ) { return src; }
512 short _pico_little_short( short src ) { return src; }
513 float _pico_little_float( float src ) { return src; }
514
515 int _pico_big_long( int src ){
516         return ( ( src & 0xFF000000 ) >> 24 ) |
517                    ( ( src & 0x00FF0000 ) >> 8 ) |
518                    ( ( src & 0x0000FF00 ) << 8 ) |
519                    ( ( src & 0x000000FF ) << 24 );
520 }
521
522 short _pico_big_short( short src ){
523         return ( ( src & 0xFF00 ) >> 8 ) |
524                    ( ( src & 0x00FF ) << 8 );
525 }
526
527 float _pico_big_float( float src ){
528         floatSwapUnion in,out;
529         in.f = src;
530         out.c[ 0 ] = in.c[ 3 ];
531         out.c[ 1 ] = in.c[ 2 ];
532         out.c[ 2 ] = in.c[ 1 ];
533         out.c[ 3 ] = in.c[ 0 ];
534         return out.f;
535 }
536 #endif /*__BIG_ENDIAN__*/
537
538 /* _pico_stristr:
539  *  case-insensitive strstr. -sea
540  */
541 const char *_pico_stristr( const char *str, const char *substr ){
542         const size_t sublen = strlen( substr );
543         while ( *str )
544         {
545                 if ( !_pico_strnicmp( str,substr,sublen ) ) {
546                         break;
547                 }
548                 str++;
549         }
550         if ( !( *str ) ) {
551                 str = NULL;
552         }
553         return str;
554 }
555
556 /*
557    _pico_unixify()
558    changes dos \ style path separators to /
559  */
560
561 void _pico_unixify( char *path ){
562         if ( path == NULL ) {
563                 return;
564         }
565         while ( *path )
566         {
567                 if ( *path == '\\' ) {
568                         *path = '/';
569                 }
570                 path++;
571         }
572 }
573
574 /* _pico_nofname:
575  *  removes file name portion from given file path and converts
576  *  the directory separators to un*x style. returns 1 on success
577  *  or 0 when 'destSize' was exceeded. -sea
578  */
579 int _pico_nofname( const char *path, char *dest, int destSize ){
580         int left  = destSize;
581         char *temp  = dest;
582
583         while ( ( *dest = *path ) != '\0' )
584         {
585                 if ( *dest == '/' || *dest == '\\' ) {
586                         temp = ( dest + 1 );
587                         *dest = '/';
588                 }
589                 dest++; path++;
590
591                 if ( --left < 1 ) {
592                         *temp = '\0';
593                         return 0;
594                 }
595         }
596         *temp = '\0';
597         return 1;
598 }
599
600 /* _pico_nopath:
601  *  returns ptr to filename portion in given path or an empty
602  *  string otherwise. given 'path' is not altered. -sea
603  */
604 const char *_pico_nopath( const char *path ){
605         const char *src;
606         src = path + ( strlen( path ) - 1 );
607
608         if ( path == NULL ) {
609                 return "";
610         }
611         if ( !strchr( path,'/' ) && !strchr( path,'\\' ) ) {
612                 return ( path );
613         }
614
615         while ( ( src-- ) != path )
616         {
617                 if ( *src == '/' || *src == '\\' ) {
618                         return ( ++src );
619                 }
620         }
621         return "";
622 }
623
624 /* _pico_setfext:
625  *  sets/changes the file extension for the given filename
626  *  or filepath's filename portion. the given 'path' *is*
627  *  altered. leave 'ext' empty to remove extension. -sea
628  */
629 char *_pico_setfext( char *path, const char *ext ){
630         char *src;
631         int remfext = 0;
632
633         src = path + ( strlen( path ) - 1 );
634
635         if ( ext == NULL ) {
636                 ext = "";
637         }
638         if ( strlen( ext ) < 1 ) {
639                 remfext = 1;
640         }
641         if ( strlen( path ) < 1 ) {
642                 return path;
643         }
644
645         while ( ( src-- ) != path )
646         {
647                 if ( *src == '/' || *src == '\\' ) {
648                         return path;
649                 }
650
651                 if ( *src == '.' ) {
652                         if ( remfext ) {
653                                 *src = '\0';
654                                 return path;
655                         }
656                         *( ++src ) = '\0';
657                         break;
658                 }
659         }
660         strcat( path,ext );
661         return path;
662 }
663
664 /* _pico_getline:
665  *  extracts one line from the given buffer and stores it in dest.
666  *  returns -1 on error or the length of the line on success. i've
667  *  removed string trimming here. this can be done manually by the
668  *  calling func.
669  */
670 int _pico_getline( char *buf, int bufsize, char *dest, int destsize ){
671         int pos;
672
673         /* check output */
674         if ( dest == NULL || destsize < 1 ) {
675                 return -1;
676         }
677         memset( dest,0,destsize );
678
679         /* check input */
680         if ( buf == NULL || bufsize < 1 ) {
681                 return -1;
682         }
683
684         /* get next line */
685         for ( pos = 0; pos < bufsize && pos < destsize; pos++ )
686         {
687                 if ( buf[pos] == '\n' ) {
688                         pos++; break;
689                 }
690                 dest[pos] = buf[pos];
691         }
692         /* terminate dest and return */
693         dest[pos] = '\0';
694         return pos;
695 }
696
697 /* _pico_parse_skip_white:
698  *  skips white spaces in current pico parser, sets *hasLFs
699  *  to 1 if linefeeds were skipped, and either returns the
700  *  parser's cursor pointer or NULL on error. -sea
701  */
702 void _pico_parse_skip_white( picoParser_t *p, int *hasLFs ){
703         /* sanity checks */
704         if ( p == NULL || p->cursor == NULL ) {
705                 return;
706         }
707
708         /* skin white spaces */
709         while ( 1 )
710         {
711                 /* sanity checks */
712                 if ( p->cursor <  p->buffer ||
713                          p->cursor >= p->max ) {
714                         return;
715                 }
716                 /* break for chars other than white spaces */
717                 if ( *p->cursor >  0x20 ) {
718                         break;
719                 }
720                 if ( *p->cursor == 0x00 ) {
721                         return;
722                 }
723
724                 /* a bit of linefeed handling */
725                 if ( *p->cursor == '\n' ) {
726                         *hasLFs = 1;
727                         p->curLine++;
728                 }
729                 /* go to next character */
730                 p->cursor++;
731         }
732 }
733
734 /* _pico_new_parser:
735  *  allocates a new ascii parser object.
736  */
737 picoParser_t *_pico_new_parser( const picoByte_t *buffer, int bufSize ){
738         picoParser_t *p;
739
740         /* sanity check */
741         if ( buffer == NULL || bufSize <= 0 ) {
742                 return NULL;
743         }
744
745         /* allocate reader */
746         p = _pico_alloc( sizeof( picoParser_t ) );
747         if ( p == NULL ) {
748                 return NULL;
749         }
750         memset( p,0,sizeof( picoParser_t ) );
751
752         /* allocate token space */
753         p->tokenSize = 0;
754         p->tokenMax = 1024;
755         p->token = _pico_alloc( p->tokenMax );
756         if ( p->token == NULL ) {
757                 _pico_free( p );
758                 return NULL;
759         }
760         /* setup */
761         p->buffer   = (const char *) buffer;
762         p->cursor   = p->buffer;
763         p->bufSize  = bufSize;
764         p->max      = p->buffer + bufSize;
765         p->curLine = 1; /* sea: new */
766
767         /* return ptr to parser */
768         return p;
769 }
770
771 /* _pico_free_parser:
772  *  frees an existing pico parser object.
773  */
774 void _pico_free_parser( picoParser_t *p ){
775         /* sanity check */
776         if ( p == NULL ) {
777                 return;
778         }
779
780         /* free the parser */
781         if ( p->token != NULL ) {
782                 _pico_free( p->token );
783         }
784         _pico_free( p );
785 }
786
787 /* _pico_parse_ex:
788  *  reads the next token from given pico parser object. if param
789  * 'allowLFs' is 1 it will read beyond linefeeds and return 0 when
790  *  the EOF is reached. if 'allowLFs' is 0 it will return 0 when
791  *  the EOL is reached. if 'handleQuoted' is 1 the parser function
792  *  will handle "quoted" strings and return the data between the
793  *  quotes as token. returns 0 on end/error or 1 on success. -sea
794  */
795 int _pico_parse_ex( picoParser_t *p, int allowLFs, int handleQuoted ){
796         int hasLFs = 0;
797         const char *old;
798
799         /* sanity checks */
800         if ( p == NULL || p->buffer == NULL ||
801                  p->cursor <  p->buffer ||
802                  p->cursor >= p->max ) {
803                 return 0;
804         }
805         /* clear parser token */
806         p->tokenSize = 0;
807         p->token[ 0 ] = '\0';
808         old = p->cursor;
809
810         /* skip whitespaces */
811         while ( p->cursor < p->max && *p->cursor <= 32 )
812         {
813                 if ( *p->cursor == '\n' ) {
814                         p->curLine++;
815                         hasLFs++;
816                 }
817                 p->cursor++;
818         }
819         /* return if we're not allowed to go beyond lfs */
820         if ( ( hasLFs > 0 ) && !allowLFs ) {
821                 p->cursor = old;
822                 return 0;
823         }
824         /* get next quoted string */
825         if ( *p->cursor == '\"' && handleQuoted ) {
826                 p->cursor++;
827                 while ( p->cursor < p->max && *p->cursor )
828                 {
829                         if ( *p->cursor == '\\' ) {
830                                 if ( *( p->cursor + 1 ) == '"' ) {
831                                         p->cursor++;
832                                 }
833                                 p->token[ p->tokenSize++ ] = *p->cursor++;
834                                 continue;
835                         }
836                         else if ( *p->cursor == '\"' ) {
837                                 p->cursor++;
838                                 break;
839                         }
840                         else if ( *p->cursor == '\n' ) {
841                                 p->curLine++;
842                         }
843                         p->token[ p->tokenSize++ ] = *p->cursor++;
844                 }
845                 /* terminate token */
846                 p->token[ p->tokenSize ] = '\0';
847                 return 1;
848         }
849         /* otherwise get next word */
850         while ( p->cursor < p->max && *p->cursor > 32 )
851         {
852                 if ( *p->cursor == '\n' ) {
853                         p->curLine++;
854                 }
855                 p->token[ p->tokenSize++ ] = *p->cursor++;
856         }
857         /* terminate token */
858         p->token[ p->tokenSize ] = '\0';
859         return 1;
860 }
861
862 /* _pico_parse_first:
863  *  reads the first token from the next line and returns
864  *  a pointer to it. returns NULL on EOL or EOF. -sea
865  */
866 char *_pico_parse_first( picoParser_t *p ){
867         /* sanity check */
868         if ( p == NULL ) {
869                 return NULL;
870         }
871
872         /* try to read next token (with lfs & quots) */
873         if ( !_pico_parse_ex( p,1,1 ) ) {
874                 return NULL;
875         }
876
877         /* return ptr to the token string */
878         return p->token;
879 }
880
881 /* _pico_parse:
882  *  reads the next token from the parser and returns a pointer
883  *  to it. quoted strings are handled as usual. returns NULL
884  *  on EOL or EOF. -sea
885  */
886 char *_pico_parse( picoParser_t *p, int allowLFs ){
887         /* sanity check */
888         if ( p == NULL ) {
889                 return NULL;
890         }
891
892         /* try to read next token (with quots) */
893         if ( !_pico_parse_ex( p,allowLFs,1 ) ) {
894                 return NULL;
895         }
896
897         /* return ptr to the token string */
898         return p->token;
899 }
900
901 /* _pico_parse_skip_rest:
902  *  skips the rest of the current line in parser.
903  */
904 void _pico_parse_skip_rest( picoParser_t *p ){
905         while ( _pico_parse_ex( p,0,0 ) ) ;
906 }
907
908 /* _pico_parse_skip_braced:
909  *  parses/skips over a braced section. returns 1 on success
910  *  or 0 on error (when there was no closing bracket and the
911  *  end of buffer was reached or when the opening bracket was
912  *  missing).
913  */
914 int _pico_parse_skip_braced( picoParser_t *p ){
915         int firstToken = 1;
916         int level;
917
918         /* sanity check */
919         if ( p == NULL ) {
920                 return 0;
921         }
922
923         /* set the initial level for parsing */
924         level = 0;
925
926         /* skip braced section */
927         while ( 1 )
928         {
929                 /* read next token (lfs allowed) */
930                 if ( !_pico_parse_ex( p,1,1 ) ) {
931                         /* end of parser buffer reached */
932                         return 0;
933                 }
934                 /* first token must be an opening bracket */
935                 if ( firstToken && p->token[0] != '{' ) {
936                         /* opening bracket missing */
937                         return 0;
938                 }
939                 /* we only check this once */
940                 firstToken = 0;
941
942                 /* update level */
943                 if ( p->token[1] == '\0' ) {
944                         if ( p->token[0] == '{' ) {
945                                 level++;
946                         }
947                         if ( p->token[0] == '}' ) {
948                                 level--;
949                         }
950                 }
951                 /* break if we're back at our starting level */
952                 if ( level == 0 ) {
953                         break;
954                 }
955         }
956         /* successfully skipped braced section */
957         return 1;
958 }
959
960 int _pico_parse_check( picoParser_t *p, int allowLFs, char *str ){
961         if ( !_pico_parse_ex( p,allowLFs,1 ) ) {
962                 return 0;
963         }
964         if ( !strcmp( p->token,str ) ) {
965                 return 1;
966         }
967         return 0;
968 }
969
970 int _pico_parse_checki( picoParser_t *p, int allowLFs, char *str ){
971         if ( !_pico_parse_ex( p,allowLFs,1 ) ) {
972                 return 0;
973         }
974         if ( !_pico_stricmp( p->token,str ) ) {
975                 return 1;
976         }
977         return 0;
978 }
979
980 int _pico_parse_int( picoParser_t *p, int *out ){
981         char *token;
982
983         /* sanity checks */
984         if ( p == NULL || out == NULL ) {
985                 return 0;
986         }
987
988         /* get token and turn it into an integer */
989         *out = 0;
990         token = _pico_parse( p,0 );
991         if ( token == NULL ) {
992                 return 0;
993         }
994         *out = atoi( token );
995
996         /* success */
997         return 1;
998 }
999
1000 int _pico_parse_int_def( picoParser_t *p, int *out, int def ){
1001         char *token;
1002
1003         /* sanity checks */
1004         if ( p == NULL || out == NULL ) {
1005                 return 0;
1006         }
1007
1008         /* get token and turn it into an integer */
1009         *out = def;
1010         token = _pico_parse( p,0 );
1011         if ( token == NULL ) {
1012                 return 0;
1013         }
1014         *out = atoi( token );
1015
1016         /* success */
1017         return 1;
1018 }
1019
1020 int _pico_parse_float( picoParser_t *p, float *out ){
1021         char *token;
1022
1023         /* sanity checks */
1024         if ( p == NULL || out == NULL ) {
1025                 return 0;
1026         }
1027
1028         /* get token and turn it into a float */
1029         *out = 0.0f;
1030         token = _pico_parse( p,0 );
1031         if ( token == NULL ) {
1032                 return 0;
1033         }
1034         *out = (float) atof( token );
1035
1036         /* success */
1037         return 1;
1038 }
1039
1040 int _pico_parse_float_def( picoParser_t *p, float *out, float def ){
1041         char *token;
1042
1043         /* sanity checks */
1044         if ( p == NULL || out == NULL ) {
1045                 return 0;
1046         }
1047
1048         /* get token and turn it into a float */
1049         *out = def;
1050         token = _pico_parse( p,0 );
1051         if ( token == NULL ) {
1052                 return 0;
1053         }
1054         *out = (float) atof( token );
1055
1056         /* success */
1057         return 1;
1058 }
1059
1060 int _pico_parse_vec( picoParser_t *p, picoVec3_t out ){
1061         char *token;
1062         int i;
1063
1064         /* sanity checks */
1065         if ( p == NULL || out == NULL ) {
1066                 return 0;
1067         }
1068
1069         /* zero out outination vector */
1070         _pico_zero_vec( out );
1071
1072         /* parse three vector components */
1073         for ( i = 0; i < 3; i++ )
1074         {
1075                 token = _pico_parse( p,0 );
1076                 if ( token == NULL ) {
1077                         _pico_zero_vec( out );
1078                         return 0;
1079                 }
1080                 out[ i ] = (float) atof( token );
1081         }
1082         /* success */
1083         return 1;
1084 }
1085
1086 int _pico_parse_vec_def( picoParser_t *p, picoVec3_t out, picoVec3_t def ){
1087         char *token;
1088         int i;
1089
1090         /* sanity checks */
1091         if ( p == NULL || out == NULL ) {
1092                 return 0;
1093         }
1094
1095         /* assign default vector value */
1096         _pico_copy_vec( def,out );
1097
1098         /* parse three vector components */
1099         for ( i = 0; i < 3; i++ )
1100         {
1101                 token = _pico_parse( p,0 );
1102                 if ( token == NULL ) {
1103                         _pico_copy_vec( def,out );
1104                         return 0;
1105                 }
1106                 out[ i ] = (float) atof( token );
1107         }
1108         /* success */
1109         return 1;
1110 }
1111
1112 int _pico_parse_vec2( picoParser_t *p, picoVec2_t out ){
1113         char *token;
1114         int i;
1115
1116         /* sanity checks */
1117         if ( p == NULL || out == NULL ) {
1118                 return 0;
1119         }
1120
1121         /* zero out outination vector */
1122         _pico_zero_vec2( out );
1123
1124         /* parse two vector components */
1125         for ( i = 0; i < 2; i++ )
1126         {
1127                 token = _pico_parse( p,0 );
1128                 if ( token == NULL ) {
1129                         _pico_zero_vec2( out );
1130                         return 0;
1131                 }
1132                 out[ i ] = (float) atof( token );
1133         }
1134         /* success */
1135         return 1;
1136 }
1137
1138 int _pico_parse_vec2_def( picoParser_t *p, picoVec2_t out, picoVec2_t def ){
1139         char *token;
1140         int i;
1141
1142         /* sanity checks */
1143         if ( p == NULL || out == NULL ) {
1144                 return 0;
1145         }
1146
1147         /* assign default vector value */
1148         _pico_copy_vec2( def,out );
1149
1150         /* parse two vector components */
1151         for ( i = 0; i < 2; i++ )
1152         {
1153                 token = _pico_parse( p,0 );
1154                 if ( token == NULL ) {
1155                         _pico_copy_vec2( def,out );
1156                         return 0;
1157                 }
1158                 out[ i ] = (float) atof( token );
1159         }
1160         /* success */
1161         return 1;
1162 }
1163
1164 int _pico_parse_vec4( picoParser_t *p, picoVec4_t out ){
1165         char *token;
1166         int i;
1167
1168         /* sanity checks */
1169         if ( p == NULL || out == NULL ) {
1170                 return 0;
1171         }
1172
1173         /* zero out outination vector */
1174         _pico_zero_vec4( out );
1175
1176         /* parse four vector components */
1177         for ( i = 0; i < 4; i++ )
1178         {
1179                 token = _pico_parse( p,0 );
1180                 if ( token == NULL ) {
1181                         _pico_zero_vec4( out );
1182                         return 0;
1183                 }
1184                 out[ i ] = (float) atof( token );
1185         }
1186         /* success */
1187         return 1;
1188 }
1189
1190 int _pico_parse_vec4_def( picoParser_t *p, picoVec4_t out, picoVec4_t def ){
1191         char *token;
1192         int i;
1193
1194         /* sanity checks */
1195         if ( p == NULL || out == NULL ) {
1196                 return 0;
1197         }
1198
1199         /* assign default vector value */
1200         _pico_copy_vec4( def,out );
1201
1202         /* parse four vector components */
1203         for ( i = 0; i < 4; i++ )
1204         {
1205                 token = _pico_parse( p,0 );
1206                 if ( token == NULL ) {
1207                         _pico_copy_vec4( def,out );
1208                         return 0;
1209                 }
1210                 out[ i ] = (float) atof( token );
1211         }
1212         /* success */
1213         return 1;
1214 }
1215
1216 /* _pico_new_memstream:
1217  *  allocates a new memorystream object.
1218  */
1219 picoMemStream_t *_pico_new_memstream( const picoByte_t *buffer, int bufSize ){
1220         picoMemStream_t *s;
1221
1222         /* sanity check */
1223         if ( buffer == NULL || bufSize <= 0 ) {
1224                 return NULL;
1225         }
1226
1227         /* allocate stream */
1228         s = _pico_alloc( sizeof( picoMemStream_t ) );
1229         if ( s == NULL ) {
1230                 return NULL;
1231         }
1232         memset( s,0,sizeof( picoMemStream_t ) );
1233
1234         /* setup */
1235         s->buffer   = buffer;
1236         s->curPos   = buffer;
1237         s->bufSize  = bufSize;
1238         s->flag     = 0;
1239
1240         /* return ptr to stream */
1241         return s;
1242 }
1243
1244 /* _pico_free_memstream:
1245  *  frees an existing pico memorystream object.
1246  */
1247 void _pico_free_memstream( picoMemStream_t *s ){
1248         /* sanity check */
1249         if ( s == NULL ) {
1250                 return;
1251         }
1252
1253         /* free the stream */
1254         _pico_free( s );
1255 }
1256
1257 /* _pico_memstream_read:
1258  *  reads data from a pico memorystream into a buffer.
1259  */
1260 int _pico_memstream_read( picoMemStream_t *s, void *buffer, int len ){
1261         int ret = 1;
1262
1263         /* sanity checks */
1264         if ( s == NULL || buffer == NULL ) {
1265                 return 0;
1266         }
1267
1268         if ( s->curPos + len > s->buffer + s->bufSize ) {
1269                 s->flag |= PICO_IOEOF;
1270                 len = s->buffer + s->bufSize - s->curPos;
1271                 ret = 0;
1272         }
1273
1274         /* read the data */
1275         memcpy( buffer, s->curPos, len );
1276         s->curPos += len;
1277         return ret;
1278 }
1279
1280 /* _pico_memstream_read:
1281  *  reads a character from a pico memorystream
1282  */
1283 int _pico_memstream_getc( picoMemStream_t *s ){
1284         int c = 0;
1285
1286         /* sanity check */
1287         if ( s == NULL ) {
1288                 return -1;
1289         }
1290
1291         /* read the character */
1292         if ( _pico_memstream_read( s, &c, 1 ) == 0 ) {
1293                 return -1;
1294         }
1295
1296         return c;
1297 }
1298
1299 /* _pico_memstream_seek:
1300  *  sets the current read position to a different location
1301  */
1302 int _pico_memstream_seek( picoMemStream_t *s, long offset, int origin ){
1303         int overflow;
1304
1305         /* sanity check */
1306         if ( s == NULL ) {
1307                 return -1;
1308         }
1309
1310         if ( origin == PICO_SEEK_SET ) {
1311                 s->curPos = s->buffer + offset;
1312                 overflow = s->curPos - ( s->buffer + s->bufSize );
1313                 if ( overflow > 0 ) {
1314                         s->curPos = s->buffer + s->bufSize;
1315                         return offset - overflow;
1316                 }
1317                 return 0;
1318         }
1319         else if ( origin == PICO_SEEK_CUR ) {
1320                 s->curPos += offset;
1321                 overflow = s->curPos - ( s->buffer + s->bufSize );
1322                 if ( overflow > 0 ) {
1323                         s->curPos = s->buffer + s->bufSize;
1324                         return offset - overflow;
1325                 }
1326                 return 0;
1327         }
1328         else if ( origin == PICO_SEEK_END ) {
1329                 s->curPos = ( s->buffer + s->bufSize ) - offset;
1330                 overflow = s->buffer - s->curPos;
1331                 if ( overflow > 0 ) {
1332                         s->curPos = s->buffer;
1333                         return offset - overflow;
1334                 }
1335                 return 0;
1336         }
1337
1338         return -1;
1339 }
1340
1341 /* _pico_memstream_tell:
1342  *  returns the current read position in the pico memorystream
1343  */
1344 long _pico_memstream_tell( picoMemStream_t *s ){
1345         /* sanity check */
1346         if ( s == NULL ) {
1347                 return -1;
1348         }
1349
1350         return s->curPos - s->buffer;
1351 }