1 /* -----------------------------------------------------------------------------
5 Copyright (c) 2002, Randy Reddig & seaw0lf
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
11 Redistributions of source code must retain the above copyright notice, this list
12 of conditions and the following disclaimer.
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.
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.
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.
33 ----------------------------------------------------------------------------- */
36 * - fix p->curLine for parser routines. increased twice
41 #include "picointernal.h"
42 #include "globaldefs.h"
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;
61 * kludged memory allocation wrapper
63 void *_pico_alloc( size_t size ){
66 /* some sanity checks */
70 if ( _pico_ptr_malloc == NULL ) {
75 ptr = _pico_ptr_malloc( size );
80 /* zero out allocated memory */
83 /* return pointer to allocated memory */
88 * _pico_calloc wrapper
90 void *_pico_calloc( size_t num, size_t size ){
93 /* some sanity checks */
94 if ( num == 0 || size == 0 ) {
97 if ( _pico_ptr_malloc == NULL ) {
101 /* allocate memory */
102 ptr = _pico_ptr_malloc( num * size );
107 /* zero out allocated memory */
108 memset( ptr,0,num * size );
110 /* return pointer to allocated memory */
115 * memory reallocation wrapper (note: only grows,
116 * but never shrinks or frees)
118 void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize ){
125 if ( newSize < oldSize ) {
128 if ( _pico_ptr_malloc == NULL ) {
132 /* allocate new pointer */
133 ptr2 = _pico_alloc( newSize );
134 if ( ptr2 == NULL ) {
139 if ( *ptr != NULL ) {
140 memcpy( ptr2, *ptr, oldSize );
144 /* fix up and return */
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
158 char *_pico_clone_alloc( const char *str ){
166 /* allocate memory */
167 cloned = _pico_alloc( strlen( str ) + 1 );
168 if ( cloned == NULL ) {
172 /* copy input string to cloned string */
173 strcpy( cloned, str );
175 /* return ptr to cloned string */
180 * wrapper around the free function pointer
182 void _pico_free( void *ptr ){
187 if ( _pico_ptr_free == NULL ) {
191 /* free the allocated memory */
192 _pico_ptr_free( ptr );
196 * wrapper around the loadfile function pointer
198 void _pico_load_file( const char *name, unsigned char **buffer, int *bufSize ){
200 if ( name == NULL ) {
204 if ( _pico_ptr_load_file == NULL ) {
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 );
214 * wrapper around the file free function pointer
216 void _pico_free_file( void *buffer ){
218 if ( buffer == NULL ) {
222 /* use default free */
223 if ( _pico_ptr_free_file == NULL ) {
227 /* free the allocated file */
228 _pico_ptr_free_file( buffer );
232 * wrapper around the print function pointer -sea
234 void _pico_printf( int level, const char *format, ... ){
239 if ( format == NULL ) {
242 if ( _pico_ptr_print == NULL ) {
247 va_start( argptr,format );
248 vsprintf( str,format,argptr );
251 /* remove linefeeds */
252 if ( str[ strlen( str ) - 1 ] == '\n' ) {
253 str[ strlen( str ) - 1 ] = '\0';
256 /* do the actual call */
257 _pico_ptr_print( level,str );
260 /* _pico_first_token:
261 * trims everything after the first whitespace-delimited token
264 void _pico_first_token( char *str ){
265 if ( !str || !*str ) {
268 while ( *str && !isspace( *str ) )
274 * left trims the given string -sea
276 char *_pico_strltrim( char *str ){
277 char *str1 = str, *str2 = str;
279 while ( isspace( *str2 ) ) str2++;
281 while ( *str2 != '\0' ) /* fix: ydnar */
288 * right trims the given string -sea
290 char *_pico_strrtrim( char *str ){
297 if ( allspace && !isspace( *str1 ) ) {
307 while ( ( isspace( *str1 ) ) && ( str1 >= str ) )
315 * pico internal string-to-lower routine.
317 char *_pico_strlwr( char *str ){
319 for ( cp = str; *cp; ++cp )
321 if ( 'A' <= *cp && *cp <= 'Z' ) {
322 *cp += ( 'a' - 'A' );
329 * counts how often the given char appears in str. -sea
331 int _pico_strchcount( char *str, int ch ){
333 while ( *str++ ) if ( *str == ch ) {
339 void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs ){
341 for ( i = 0; i < 3; i++ )
348 void _pico_expand_bounds( picoVec3_t p, picoVec3_t mins, picoVec3_t maxs ){
350 for ( i = 0; i < 3; i++ )
353 if ( value < mins[i] ) {
356 if ( value > maxs[i] ) {
362 void _pico_zero_vec( picoVec3_t vec ){
363 vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = 0;
366 void _pico_zero_vec2( picoVec2_t vec ){
367 vec[ 0 ] = vec[ 1 ] = 0;
370 void _pico_zero_vec4( picoVec4_t vec ){
371 vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = vec[ 3 ] = 0;
374 void _pico_set_vec( picoVec3_t v, float a, float b, float c ){
380 void _pico_set_vec4( picoVec4_t v, float a, float b, float c, float d ){
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 ];
393 void _pico_copy_vec2( picoVec2_t src, picoVec2_t dest ){
394 dest[ 0 ] = src[ 0 ];
395 dest[ 1 ] = src[ 1 ];
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 ];
406 picoVec_t _pico_normalize_vec( picoVec3_t vec ){
409 len = sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] + vec[ 2 ] * vec[ 2 ] );
414 vec[ 0 ] *= (picoVec_t) ilen;
415 vec[ 1 ] *= (picoVec_t) ilen;
416 vec[ 2 ] *= (picoVec_t) ilen;
417 return (picoVec_t) len;
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 ];
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 ];
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;
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;
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 ];
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 ];
455 picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVec3_t c ){
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 );
465 const picoColor_t picoColor_white = { 255, 255, 255, 255 };
467 /* separate from _pico_set_vec4 */
468 void _pico_set_color( picoColor_t c, int r, int g, int b, int a ){
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 ];
482 #if GDEF_ARCH_ENDIAN_BIG
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; }
488 int _pico_little_long( int src ){
489 return ( ( src & 0xFF000000 ) >> 24 ) |
490 ( ( src & 0x00FF0000 ) >> 8 ) |
491 ( ( src & 0x0000FF00 ) << 8 ) |
492 ( ( src & 0x000000FF ) << 24 );
495 short _pico_little_short( short src ){
496 return ( ( src & 0xFF00 ) >> 8 ) |
497 ( ( src & 0x00FF ) << 8 );
500 float _pico_little_float( float src ){
501 floatSwapUnion in,out;
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 ];
509 #else /*__BIG_ENDIAN__*/
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; }
515 int _pico_big_long( int src ){
516 return ( ( src & 0xFF000000 ) >> 24 ) |
517 ( ( src & 0x00FF0000 ) >> 8 ) |
518 ( ( src & 0x0000FF00 ) << 8 ) |
519 ( ( src & 0x000000FF ) << 24 );
522 short _pico_big_short( short src ){
523 return ( ( src & 0xFF00 ) >> 8 ) |
524 ( ( src & 0x00FF ) << 8 );
527 float _pico_big_float( float src ){
528 floatSwapUnion in,out;
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 ];
536 #endif /*__BIG_ENDIAN__*/
539 * case-insensitive strstr. -sea
541 const char *_pico_stristr( const char *str, const char *substr ){
542 const size_t sublen = strlen( substr );
545 if ( !_pico_strnicmp( str,substr,sublen ) ) {
558 changes dos \ style path separators to /
561 void _pico_unixify( char *path ){
562 if ( path == NULL ) {
567 if ( *path == '\\' ) {
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
579 int _pico_nofname( const char *path, char *dest, int destSize ){
583 while ( ( *dest = *path ) != '\0' )
585 if ( *dest == '/' || *dest == '\\' ) {
601 * returns ptr to filename portion in given path or an empty
602 * string otherwise. given 'path' is not altered. -sea
604 const char *_pico_nopath( const char *path ){
606 src = path + ( strlen( path ) - 1 );
608 if ( path == NULL ) {
611 if ( !strchr( path,'/' ) && !strchr( path,'\\' ) ) {
615 while ( ( src-- ) != path )
617 if ( *src == '/' || *src == '\\' ) {
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
629 char *_pico_setfext( char *path, const char *ext ){
633 src = path + ( strlen( path ) - 1 );
638 if ( strlen( ext ) < 1 ) {
641 if ( strlen( path ) < 1 ) {
645 while ( ( src-- ) != path )
647 if ( *src == '/' || *src == '\\' ) {
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
670 int _pico_getline( char *buf, int bufsize, char *dest, int destsize ){
674 if ( dest == NULL || destsize < 1 ) {
677 memset( dest,0,destsize );
680 if ( buf == NULL || bufsize < 1 ) {
685 for ( pos = 0; pos < bufsize && pos < destsize; pos++ )
687 if ( buf[pos] == '\n' ) {
690 dest[pos] = buf[pos];
692 /* terminate dest and return */
697 /* expecting fileName to be relative vfs model path */
698 void _pico_deduce_shadername( const char* fileName, const char* srcName, picoShader_t* shader ){
699 if( srcName == NULL || fileName == NULL )
701 char name[strlen( srcName ) + 1];
702 strcpy( name, srcName );
703 _pico_unixify( name );
704 _pico_setfext( name, NULL );
706 char path[strlen( fileName ) + strlen( name ) + 1];
707 _pico_nofname( fileName, path, strlen( fileName ) + strlen( name ) + 1 );
708 _pico_unixify( path );
710 if( !strchr( name , '/' ) ){ /* texture is likely in the folder, where model is */
711 strcat( path, name );
713 else if( name[0] == '/' || ( name[0] != '\0' && name[1] == ':' ) || strstr( name, ".." ) ){ /* absolute path or with .. */
714 const char* p = name;
715 for (; *p != '\0'; ++p )
716 if ( _pico_strnicmp( p, "/models/", 8 ) == 0 || _pico_strnicmp( p, "/textures/", 10 ) == 0 )
719 strcpy( path, p + 1 );
722 p = _pico_nopath( name );
727 PicoSetShaderName( shader, name );
731 _pico_printf( PICO_NORMAL, "PICO: substituting shader name: %s -> %s", srcName, path );
732 PicoSetShaderName( shader, path );
735 /* deduce shadernames from bitmap or shadername paths */
736 void _pico_deduce_shadernames( picoModel_t *model ){
737 for ( int i = 0; i < model->numShaders; ++i ){
738 /* skip null shaders */
739 if ( model->shader[i] == NULL )
742 const char* mapname = model->shader[i]->mapName;
743 const char* shadername = model->shader[i]->name;
745 /* Detect intentional material name to not replace it with texture name.
747 Reimplement commits by Garux:
748 https://github.com/Garux/netradiant-custom/commit/1bd3e7ae186b55fb61e3738d2493432c0b1f5a7b
749 https://github.com/Garux/netradiant-custom/commit/ea21eee2254fb2e667732d8f1b0f83c439a89bfa
751 This attempts to restore proper material behaviour when the mapper knows what he is doing,
752 also called Julius' case or correct case because Julius is always correctâ„¢
753 while keeping the fallback for other situations, also called newbie's case
754 which may be compatible with third-party tools not following Quake 3 conventions.
756 See: https://gitlab.com/xonotic/netradiant/-/merge_requests/179#note_777324051 */
757 if ( shadername && *shadername &&
758 ( _pico_strnicmp( shadername, "models/", 7 ) == 0
759 || _pico_strnicmp( shadername, "models\\", 7 ) == 0
760 || _pico_strnicmp( shadername, "textures/", 9 ) == 0
761 || _pico_strnicmp( shadername, "textures\\", 9 ) == 0 ) )
763 _pico_deduce_shadername( model->fileName, shadername, model->shader[i] );
765 else if( mapname && *mapname )
766 _pico_deduce_shadername( model->fileName, mapname, model->shader[i] );
767 else if( shadername && *shadername )
768 _pico_deduce_shadername( model->fileName, shadername, model->shader[i] );
772 /* _pico_parse_skip_white:
773 * skips white spaces in current pico parser, sets *hasLFs
774 * to 1 if linefeeds were skipped, and either returns the
775 * parser's cursor pointer or NULL on error. -sea
777 void _pico_parse_skip_white( picoParser_t *p, int *hasLFs ){
779 if ( p == NULL || p->cursor == NULL ) {
783 /* skin white spaces */
787 if ( p->cursor < p->buffer ||
788 p->cursor >= p->max ) {
791 /* break for chars other than white spaces */
792 if ( *p->cursor > 0x20 ) {
795 if ( *p->cursor == 0x00 ) {
799 /* a bit of linefeed handling */
800 if ( *p->cursor == '\n' ) {
804 /* go to next character */
810 * allocates a new ascii parser object.
812 picoParser_t *_pico_new_parser( const picoByte_t *buffer, int bufSize ){
816 if ( buffer == NULL || bufSize <= 0 ) {
820 /* allocate reader */
821 p = _pico_alloc( sizeof( picoParser_t ) );
825 memset( p,0,sizeof( picoParser_t ) );
827 /* allocate token space */
830 p->token = _pico_alloc( p->tokenMax );
831 if ( p->token == NULL ) {
836 p->buffer = (const char *) buffer;
837 p->cursor = p->buffer;
838 p->bufSize = bufSize;
839 p->max = p->buffer + bufSize;
840 p->curLine = 1; /* sea: new */
842 /* return ptr to parser */
846 /* _pico_free_parser:
847 * frees an existing pico parser object.
849 void _pico_free_parser( picoParser_t *p ){
855 /* free the parser */
856 if ( p->token != NULL ) {
857 _pico_free( p->token );
863 * reads the next token from given pico parser object. if param
864 * 'allowLFs' is 1 it will read beyond linefeeds and return 0 when
865 * the EOF is reached. if 'allowLFs' is 0 it will return 0 when
866 * the EOL is reached. if 'handleQuoted' is 1 the parser function
867 * will handle "quoted" strings and return the data between the
868 * quotes as token. returns 0 on end/error or 1 on success. -sea
870 int _pico_parse_ex( picoParser_t *p, int allowLFs, int handleQuoted ){
875 if ( p == NULL || p->buffer == NULL ||
876 p->cursor < p->buffer ||
877 p->cursor >= p->max ) {
880 /* clear parser token */
882 p->token[ 0 ] = '\0';
885 /* skip whitespaces */
886 while ( p->cursor < p->max && *p->cursor <= 32 )
888 if ( *p->cursor == '\n' ) {
894 /* return if we're not allowed to go beyond lfs */
895 if ( ( hasLFs > 0 ) && !allowLFs ) {
899 /* get next quoted string */
900 if ( *p->cursor == '\"' && handleQuoted ) {
902 while ( p->cursor < p->max && *p->cursor )
904 if ( *p->cursor == '\\' ) {
905 if ( *( p->cursor + 1 ) == '"' ) {
908 p->token[ p->tokenSize++ ] = *p->cursor++;
911 else if ( *p->cursor == '\"' ) {
915 else if ( *p->cursor == '\n' ) {
918 p->token[ p->tokenSize++ ] = *p->cursor++;
920 /* terminate token */
921 p->token[ p->tokenSize ] = '\0';
924 /* otherwise get next word */
925 while ( p->cursor < p->max && *p->cursor > 32 )
927 if ( *p->cursor == '\n' ) {
930 p->token[ p->tokenSize++ ] = *p->cursor++;
932 /* terminate token */
933 p->token[ p->tokenSize ] = '\0';
937 /* _pico_parse_first:
938 * reads the first token from the next line and returns
939 * a pointer to it. returns NULL on EOL or EOF. -sea
941 char *_pico_parse_first( picoParser_t *p ){
947 /* try to read next token (with lfs & quots) */
948 if ( !_pico_parse_ex( p,1,1 ) ) {
952 /* return ptr to the token string */
957 * reads the next token from the parser and returns a pointer
958 * to it. quoted strings are handled as usual. returns NULL
959 * on EOL or EOF. -sea
961 char *_pico_parse( picoParser_t *p, int allowLFs ){
967 /* try to read next token (with quots) */
968 if ( !_pico_parse_ex( p,allowLFs,1 ) ) {
972 /* return ptr to the token string */
976 /* _pico_parse_skip_rest:
977 * skips the rest of the current line in parser.
979 void _pico_parse_skip_rest( picoParser_t *p ){
980 while ( _pico_parse_ex( p,0,0 ) ) ;
983 /* _pico_parse_skip_braced:
984 * parses/skips over a braced section. returns 1 on success
985 * or 0 on error (when there was no closing bracket and the
986 * end of buffer was reached or when the opening bracket was
989 int _pico_parse_skip_braced( picoParser_t *p ){
998 /* set the initial level for parsing */
1001 /* skip braced section */
1004 /* read next token (lfs allowed) */
1005 if ( !_pico_parse_ex( p,1,1 ) ) {
1006 /* end of parser buffer reached */
1009 /* first token must be an opening bracket */
1010 if ( firstToken && p->token[0] != '{' ) {
1011 /* opening bracket missing */
1014 /* we only check this once */
1018 if ( p->token[1] == '\0' ) {
1019 if ( p->token[0] == '{' ) {
1022 if ( p->token[0] == '}' ) {
1026 /* break if we're back at our starting level */
1031 /* successfully skipped braced section */
1035 int _pico_parse_check( picoParser_t *p, int allowLFs, char *str ){
1036 if ( !_pico_parse_ex( p,allowLFs,1 ) ) {
1039 if ( !strcmp( p->token,str ) ) {
1045 int _pico_parse_checki( picoParser_t *p, int allowLFs, char *str ){
1046 if ( !_pico_parse_ex( p,allowLFs,1 ) ) {
1049 if ( !_pico_stricmp( p->token,str ) ) {
1055 int _pico_parse_int( picoParser_t *p, int *out ){
1059 if ( p == NULL || out == NULL ) {
1063 /* get token and turn it into an integer */
1065 token = _pico_parse( p,0 );
1066 if ( token == NULL ) {
1069 *out = atoi( token );
1075 int _pico_parse_int_def( picoParser_t *p, int *out, int def ){
1079 if ( p == NULL || out == NULL ) {
1083 /* get token and turn it into an integer */
1085 token = _pico_parse( p,0 );
1086 if ( token == NULL ) {
1089 *out = atoi( token );
1095 int _pico_parse_float( picoParser_t *p, float *out ){
1099 if ( p == NULL || out == NULL ) {
1103 /* get token and turn it into a float */
1105 token = _pico_parse( p,0 );
1106 if ( token == NULL ) {
1109 *out = (float) atof( token );
1115 int _pico_parse_float_def( picoParser_t *p, float *out, float def ){
1119 if ( p == NULL || out == NULL ) {
1123 /* get token and turn it into a float */
1125 token = _pico_parse( p,0 );
1126 if ( token == NULL ) {
1129 *out = (float) atof( token );
1135 int _pico_parse_vec( picoParser_t *p, picoVec3_t out ){
1140 if ( p == NULL || out == NULL ) {
1144 /* zero out outination vector */
1145 _pico_zero_vec( out );
1147 /* parse three vector components */
1148 for ( i = 0; i < 3; i++ )
1150 token = _pico_parse( p,0 );
1151 if ( token == NULL ) {
1152 _pico_zero_vec( out );
1155 out[ i ] = (float) atof( token );
1161 int _pico_parse_vec_def( picoParser_t *p, picoVec3_t out, picoVec3_t def ){
1166 if ( p == NULL || out == NULL ) {
1170 /* assign default vector value */
1171 _pico_copy_vec( def,out );
1173 /* parse three vector components */
1174 for ( i = 0; i < 3; i++ )
1176 token = _pico_parse( p,0 );
1177 if ( token == NULL ) {
1178 _pico_copy_vec( def,out );
1181 out[ i ] = (float) atof( token );
1187 int _pico_parse_vec2( picoParser_t *p, picoVec2_t out ){
1192 if ( p == NULL || out == NULL ) {
1196 /* zero out outination vector */
1197 _pico_zero_vec2( out );
1199 /* parse two vector components */
1200 for ( i = 0; i < 2; i++ )
1202 token = _pico_parse( p,0 );
1203 if ( token == NULL ) {
1204 _pico_zero_vec2( out );
1207 out[ i ] = (float) atof( token );
1213 int _pico_parse_vec2_def( picoParser_t *p, picoVec2_t out, picoVec2_t def ){
1218 if ( p == NULL || out == NULL ) {
1222 /* assign default vector value */
1223 _pico_copy_vec2( def,out );
1225 /* parse two vector components */
1226 for ( i = 0; i < 2; i++ )
1228 token = _pico_parse( p,0 );
1229 if ( token == NULL ) {
1230 _pico_copy_vec2( def,out );
1233 out[ i ] = (float) atof( token );
1239 int _pico_parse_vec4( picoParser_t *p, picoVec4_t out ){
1244 if ( p == NULL || out == NULL ) {
1248 /* zero out outination vector */
1249 _pico_zero_vec4( out );
1251 /* parse four vector components */
1252 for ( i = 0; i < 4; i++ )
1254 token = _pico_parse( p,0 );
1255 if ( token == NULL ) {
1256 _pico_zero_vec4( out );
1259 out[ i ] = (float) atof( token );
1265 int _pico_parse_vec4_def( picoParser_t *p, picoVec4_t out, picoVec4_t def ){
1270 if ( p == NULL || out == NULL ) {
1274 /* assign default vector value */
1275 _pico_copy_vec4( def,out );
1277 /* parse four vector components */
1278 for ( i = 0; i < 4; i++ )
1280 token = _pico_parse( p,0 );
1281 if ( token == NULL ) {
1282 _pico_copy_vec4( def,out );
1285 out[ i ] = (float) atof( token );
1291 /* _pico_new_memstream:
1292 * allocates a new memorystream object.
1294 picoMemStream_t *_pico_new_memstream( const picoByte_t *buffer, int bufSize ){
1298 if ( buffer == NULL || bufSize <= 0 ) {
1302 /* allocate stream */
1303 s = _pico_alloc( sizeof( picoMemStream_t ) );
1307 memset( s,0,sizeof( picoMemStream_t ) );
1312 s->bufSize = bufSize;
1315 /* return ptr to stream */
1319 /* _pico_free_memstream:
1320 * frees an existing pico memorystream object.
1322 void _pico_free_memstream( picoMemStream_t *s ){
1328 /* free the stream */
1332 /* _pico_memstream_read:
1333 * reads data from a pico memorystream into a buffer.
1335 int _pico_memstream_read( picoMemStream_t *s, void *buffer, int len ){
1339 if ( s == NULL || buffer == NULL ) {
1343 if ( s->curPos + len > s->buffer + s->bufSize ) {
1344 s->flag |= PICO_IOEOF;
1345 len = s->buffer + s->bufSize - s->curPos;
1350 memcpy( buffer, s->curPos, len );
1355 /* _pico_memstream_read:
1356 * reads a character from a pico memorystream
1358 int _pico_memstream_getc( picoMemStream_t *s ){
1366 /* read the character */
1367 if ( _pico_memstream_read( s, &c, 1 ) == 0 ) {
1374 /* _pico_memstream_seek:
1375 * sets the current read position to a different location
1377 int _pico_memstream_seek( picoMemStream_t *s, long offset, int origin ){
1385 if ( origin == PICO_SEEK_SET ) {
1386 s->curPos = s->buffer + offset;
1387 overflow = s->curPos - ( s->buffer + s->bufSize );
1388 if ( overflow > 0 ) {
1389 s->curPos = s->buffer + s->bufSize;
1390 return offset - overflow;
1394 else if ( origin == PICO_SEEK_CUR ) {
1395 s->curPos += offset;
1396 overflow = s->curPos - ( s->buffer + s->bufSize );
1397 if ( overflow > 0 ) {
1398 s->curPos = s->buffer + s->bufSize;
1399 return offset - overflow;
1403 else if ( origin == PICO_SEEK_END ) {
1404 s->curPos = ( s->buffer + s->bufSize ) - offset;
1405 overflow = s->buffer - s->curPos;
1406 if ( overflow > 0 ) {
1407 s->curPos = s->buffer;
1408 return offset - overflow;
1416 /* _pico_memstream_tell:
1417 * returns the current read position in the pico memorystream
1419 long _pico_memstream_tell( picoMemStream_t *s ){
1425 return s->curPos - s->buffer;