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