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