]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - libs/picomodel/picointernal.c
set eol-style
[xonotic/netradiant.git] / libs / picomodel / picointernal.c
index 6afae90ae05c85d2138fcab80fb4434adb94be7c..3e32dd0827629c4f92832f11f8635e4a5404b0de 100644 (file)
-/* -----------------------------------------------------------------------------\r
-\r
-PicoModel Library\r
-\r
-Copyright (c) 2002, Randy Reddig & seaw0lf\r
-All rights reserved.\r
-\r
-Redistribution and use in source and binary forms, with or without modification,\r
-are permitted provided that the following conditions are met:\r
-\r
-Redistributions of source code must retain the above copyright notice, this list\r
-of conditions and the following disclaimer.\r
-\r
-Redistributions in binary form must reproduce the above copyright notice, this\r
-list of conditions and the following disclaimer in the documentation and/or\r
-other materials provided with the distribution.\r
-\r
-Neither the names of the copyright holders nor the names of its contributors may\r
-be used to endorse or promote products derived from this software without\r
-specific prior written permission.\r
-\r
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\r
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
-\r
------------------------------------------------------------------------------ */\r
-\r
-\r
-\r
-/* marker */\r
-#define PICOINTERNAL_C\r
-\r
-\r
-\r
-/* todo:\r
- * - fix p->curLine for parser routines. increased twice\r
- */\r
-\r
-/* dependencies */\r
-#include <string.h>\r
-#include "picointernal.h"\r
-\r
-\r
-\r
-/* function pointers */\r
-void *(*_pico_ptr_malloc       )( size_t ) = malloc;\r
-void  (*_pico_ptr_free         )( void* ) = free;\r
-void  (*_pico_ptr_load_file    )( char*, unsigned char**, int* ) = NULL;\r
-void  (*_pico_ptr_free_file    )( void* ) = NULL;\r
-void  (*_pico_ptr_print                )( int, const char* ) = NULL;\r
-\r
-typedef union\r
-{\r
-       float   f;\r
-       char    c[4];\r
-}\r
-floatSwapUnion;\r
-\r
-/* _pico_alloc:\r
- *  kludged memory allocation wrapper\r
- */\r
-void *_pico_alloc( size_t size )\r
-{\r
-       void *ptr;\r
-\r
-       /* some sanity checks */\r
-       if( size == 0 )\r
-               return NULL;\r
-       if (_pico_ptr_malloc == NULL)\r
-               return NULL;\r
-\r
-       /* allocate memory */\r
-       ptr = _pico_ptr_malloc(size);\r
-       if (ptr == NULL)\r
-               return NULL;\r
-\r
-       /* zero out allocated memory */\r
-       memset(ptr,0,size);\r
-\r
-       /* return pointer to allocated memory */\r
-       return ptr;\r
-}\r
-\r
-/* _pico_calloc:\r
- *  _pico_calloc wrapper\r
- */\r
-void *_pico_calloc( size_t num, size_t size )\r
-{\r
-       void *ptr;\r
-\r
-       /* some sanity checks */\r
-       if( num == 0 || size == 0 )\r
-               return NULL;\r
-       if (_pico_ptr_malloc == NULL)\r
-               return NULL;\r
-\r
-       /* allocate memory */\r
-       ptr = _pico_ptr_malloc(num*size);\r
-       if (ptr == NULL)\r
-               return NULL;\r
-\r
-       /* zero out allocated memory */\r
-       memset(ptr,0,num*size);\r
-\r
-       /* return pointer to allocated memory */\r
-       return ptr;\r
-}\r
-\r
-/* _pico_realloc:\r
- *  memory reallocation wrapper (note: only grows,\r
- *  but never shrinks or frees)\r
- */\r
-void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize )\r
-{\r
-       void *ptr2;\r
-       \r
-       /* sanity checks */\r
-       if( ptr == NULL )\r
-               return NULL;\r
-       if( newSize < oldSize )\r
-               return *ptr;\r
-       if (_pico_ptr_malloc == NULL)\r
-               return NULL;\r
-\r
-       /* allocate new pointer */\r
-       ptr2 = _pico_alloc( newSize );\r
-       if( ptr2 == NULL )\r
-               return NULL;\r
-\r
-       /* copy */\r
-       if( *ptr != NULL )\r
-       {\r
-               memcpy( ptr2, *ptr, oldSize );\r
-               _pico_free( *ptr );\r
-       }\r
-       \r
-       /* fix up and return */\r
-       *ptr = ptr2;\r
-       return *ptr;\r
-}\r
-\r
-/* _pico_clone_alloc:\r
- *  handy function for quick string allocation/copy. it clones\r
- *  the given string and returns a pointer to the new allocated\r
- *  clone (which must be freed by caller of course) or returns\r
- *  NULL on memory alloc or param errors. if 'size' is -1 the\r
- *  length of the input string is used, otherwise 'size' is used\r
- *  as custom clone size (the string is cropped to fit into mem\r
- *  if needed). -sea\r
- */\r
-char *_pico_clone_alloc( char *str, int size )\r
-{\r
-       char  *cloned;\r
-       size_t cloneSize;\r
-\r
-       /* sanity check */\r
-       if (str == NULL) return NULL;\r
-\r
-       /* set real size of cloned string */\r
-       cloneSize = (size < 0) ? strlen(str) : size;\r
-\r
-       /* allocate memory */\r
-       cloned = _pico_alloc( cloneSize+1 ); /* bugfix! */\r
-       if (cloned == NULL)\r
-               return NULL;\r
-\r
-       /* zero out memory allocated by cloned string */\r
-       memset( cloned,0,cloneSize );\r
-\r
-       /* copy input string to cloned string */\r
-       if (cloneSize < strlen( str )) {\r
-               memcpy( cloned,str,cloneSize );\r
-               cloned[ cloneSize ] = '\0';\r
-       } else {\r
-               strcpy( cloned,str );\r
-       }\r
-       /* return ptr to cloned string */\r
-       return cloned;\r
-}\r
-\r
-/* _pico_free:\r
- * wrapper around the free function pointer\r
- */\r
-void _pico_free( void *ptr )\r
-{\r
-       /* sanity checks */\r
-       if( ptr == NULL )\r
-               return;\r
-       if (_pico_ptr_free == NULL)\r
-               return;\r
-\r
-       /* free the allocated memory */\r
-               _pico_ptr_free( ptr );\r
-}\r
-\r
-/* _pico_load_file:\r
- * wrapper around the loadfile function pointer\r
- */\r
-void _pico_load_file( char *name, unsigned char **buffer, int *bufSize )\r
-{\r
-       /* sanity checks */\r
-       if( name == NULL )\r
-       {\r
-               *bufSize = -1;\r
-               return;\r
-       }\r
-       if (_pico_ptr_load_file == NULL)\r
-       {\r
-               *bufSize = -1;\r
-               return;\r
-       }\r
-       /* do the actual call to read in the file; */\r
-       /* BUFFER IS ALLOCATED BY THE EXTERNAL LOADFILE FUNC */\r
-       _pico_ptr_load_file( name,buffer,bufSize );\r
-}\r
-\r
-/* _pico_free_file:\r
- * wrapper around the file free function pointer\r
- */\r
-void _pico_free_file( void *buffer )\r
-{\r
-       /* sanity checks */\r
-       if( buffer == NULL )\r
-               return;\r
-\r
-       /* use default free */\r
-       if( _pico_ptr_free_file == NULL )\r
-       {\r
-               free( buffer );\r
-               return;\r
-       }\r
-       /* free the allocated file */\r
-       _pico_ptr_free_file( buffer );\r
-}\r
-\r
-/* _pico_printf:\r
- * wrapper around the print function pointer -sea\r
- */\r
-void _pico_printf( int level, const char *format, ...)\r
-{\r
-       char    str[4096];\r
-       va_list argptr;\r
-\r
-       /* sanity checks */\r
-       if( format == NULL )\r
-               return;\r
-       if (_pico_ptr_print == NULL)\r
-               return;\r
-\r
-       /* format string */\r
-       va_start( argptr,format );\r
-       vsprintf( str,format,argptr );\r
-       va_end( argptr );\r
-\r
-       /* remove linefeeds */\r
-       if (str[ strlen(str)-1 ] == '\n')\r
-               str[ strlen(str)-1 ] = '\0';\r
-\r
-       /* do the actual call */\r
-       _pico_ptr_print( level,str );\r
-}\r
-\r
-/* _pico_strltrim:\r
- *   left trims the given string -sea\r
- */\r
-char *_pico_strltrim( char *str )\r
-{\r
-       char *str1 = str, *str2 = str;\r
-\r
-       while (isspace(*str2)) str2++;\r
-       if( str2 != str )\r
-               while( *str2 != '\0' ) /* fix: ydnar */\r
-                       *str1++ = *str2++;\r
-       return str;\r
-}\r
-\r
-/* _pico_strrtrim:\r
- *   right trims the given string -sea\r
- */\r
-char *_pico_strrtrim( char *str )\r
-{\r
-       if (str && *str)\r
-       {\r
-               char *str1 = str;\r
-               int allspace = 1;\r
-\r
-               while (*str1)\r
-               {\r
-                       if (allspace && !isspace(*str1)) allspace = 0;\r
-                       str1++;\r
-               }\r
-               if (allspace) *str = '\0';\r
-               else {\r
-                       str1--;\r
-                       while ((isspace(*str1)) && (str1 >= str))\r
-                               *str1-- = '\0';\r
-               }\r
-       }\r
-    return str;\r
-}\r
-\r
-/* _pico_strlwr:\r
- *  pico internal string-to-lower routine.\r
- */\r
-char *_pico_strlwr( char *str )\r
-{\r
-       char *cp;\r
-       for (cp=str; *cp; ++cp)\r
-       {\r
-               if ('A' <= *cp && *cp <= 'Z')\r
-               {\r
-                       *cp += ('a' - 'A');\r
-               }\r
-       }\r
-       return str;\r
-}\r
-\r
-/* _pico_strchcount:\r
- *  counts how often the given char appears in str. -sea\r
- */\r
-int _pico_strchcount( char *str, int ch )\r
-{\r
-       int count = 0;\r
-       while (*str++) if (*str == ch) count++;\r
-       return count;\r
-}\r
-\r
-void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs )\r
-{\r
-       int i;\r
-       for (i=0; i<3; i++)\r
-       {\r
-               mins[i] = +999999;\r
-               maxs[i] = -999999;\r
-       }\r
-}\r
-\r
-void _pico_expand_bounds( picoVec3_t p, picoVec3_t mins, picoVec3_t maxs )\r
-{\r
-       int i;\r
-       for (i=0; i<3; i++)\r
-       {\r
-               float value = p[i];\r
-               if (value < mins[i]) mins[i] = value;\r
-               if (value > maxs[i]) maxs[i] = value;\r
-       }\r
-}\r
-\r
-void _pico_zero_vec( picoVec3_t vec )\r
-{\r
-       vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = 0;\r
-}\r
-\r
-void _pico_zero_vec2( picoVec2_t vec )\r
-{\r
-       vec[ 0 ] = vec[ 1 ] = 0;\r
-}\r
-\r
-void _pico_zero_vec4( picoVec4_t vec )\r
-{\r
-       vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = vec[ 3 ] = 0;\r
-}\r
-\r
-void _pico_set_vec( picoVec3_t v, float a, float b, float c )\r
-{\r
-       v[ 0 ] = a;\r
-       v[ 1 ] = b;\r
-       v[ 2 ] = c;\r
-}\r
-\r
-void _pico_set_vec4( picoVec4_t v, float a, float b, float c, float d )\r
-{\r
-       v[ 0 ] = a;\r
-       v[ 1 ] = b;\r
-       v[ 2 ] = c;\r
-       v[ 3 ] = d;\r
-}\r
-\r
-void _pico_copy_vec( picoVec3_t src, picoVec3_t dest )\r
-{\r
-       dest[ 0 ] = src[ 0 ];\r
-       dest[ 1 ] = src[ 1 ];\r
-       dest[ 2 ] = src[ 2 ];\r
-}\r
-\r
-void _pico_copy_vec2( picoVec2_t src, picoVec2_t dest )\r
-{\r
-       dest[ 0 ] = src[ 0 ];\r
-       dest[ 1 ] = src[ 1 ];\r
-}\r
-\r
-void _pico_copy_vec4( picoVec4_t src, picoVec4_t dest )\r
-{\r
-       dest[ 0 ] = src[ 0 ];\r
-       dest[ 1 ] = src[ 1 ];\r
-       dest[ 2 ] = src[ 2 ];\r
-       dest[ 3 ] = src[ 3 ];\r
-}\r
-\r
-/* ydnar */\r
-picoVec_t _pico_normalize_vec( picoVec3_t vec )\r
-{\r
-       double  len, ilen;\r
-       \r
-       len = sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] + vec[ 2 ] * vec[ 2 ] );\r
-       if( len == 0.0 ) return 0.0;\r
-       ilen = 1.0 / len;\r
-       vec[ 0 ] *= (picoVec_t) ilen;\r
-       vec[ 1 ] *= (picoVec_t) ilen;\r
-       vec[ 2 ] *= (picoVec_t) ilen;\r
-       return (picoVec_t) len;\r
-}\r
-\r
-void _pico_add_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest )\r
-{\r
-       dest[ 0 ] = a[ 0 ] + b[ 0 ];\r
-       dest[ 1 ] = a[ 1 ] + b[ 1 ];\r
-       dest[ 2 ] = a[ 2 ] + b[ 2 ];\r
-}\r
-\r
-void _pico_subtract_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest )\r
-{\r
-       dest[ 0 ] = a[ 0 ] - b[ 0 ];\r
-       dest[ 1 ] = a[ 1 ] - b[ 1 ];\r
-       dest[ 2 ] = a[ 2 ] - b[ 2 ];\r
-}\r
-\r
-void _pico_scale_vec( picoVec3_t v, float scale, picoVec3_t dest )\r
-{\r
-       dest[ 0 ] = v[ 0 ] * scale;\r
-       dest[ 1 ] = v[ 1 ] * scale;\r
-       dest[ 2 ] = v[ 2 ] * scale;\r
-}\r
-\r
-void _pico_scale_vec4( picoVec4_t v, float scale, picoVec4_t dest )\r
-{\r
-       dest[ 0 ] = v[ 0 ] * scale;\r
-       dest[ 1 ] = v[ 1 ] * scale;\r
-       dest[ 2 ] = v[ 2 ] * scale;\r
-       dest[ 3 ] = v[ 3 ] * scale;\r
-}\r
-\r
-picoVec_t _pico_dot_vec( picoVec3_t a, picoVec3_t b )\r
-{\r
-       return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ];\r
-}\r
-\r
-void _pico_cross_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest )\r
-{\r
-       dest[ 0 ] = a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ];\r
-       dest[ 1 ] = a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ];\r
-       dest[ 2 ] = a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ];\r
-}\r
-\r
-picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVec3_t c )\r
-{\r
-       picoVec3_t      ba, ca;\r
-\r
-       _pico_subtract_vec( b, a, ba );\r
-       _pico_subtract_vec( c, a, ca );\r
-       _pico_cross_vec( ca, ba, plane );\r
-       plane[ 3 ] = _pico_dot_vec( a, plane );\r
-       return _pico_normalize_vec( plane );\r
-}\r
-\r
-/* separate from _pico_set_vec4 */\r
-void _pico_set_color( picoColor_t c, int r, int g, int b, int a )\r
-{\r
-       c[ 0 ] = r;\r
-       c[ 1 ] = g;\r
-       c[ 2 ] = b;\r
-       c[ 3 ] = a;\r
-}\r
-\r
-void _pico_copy_color( picoColor_t src, picoColor_t dest )\r
-{\r
-       dest[ 0 ] = src[ 0 ];\r
-       dest[ 1 ] = src[ 1 ];\r
-       dest[ 2 ] = src[ 2 ];\r
-       dest[ 3 ] = src[ 3 ];\r
-}\r
-\r
-#ifdef __BIG_ENDIAN__\r
-\r
-int   _pico_big_long ( int   src ) { return src; }\r
-short _pico_big_short( short src ) { return src; }\r
-float _pico_big_float( float src ) { return src; }\r
-\r
-int _pico_little_long( int src )\r
-{\r
-       return ((src & 0xFF000000) >> 24) |\r
-                  ((src & 0x00FF0000) >> 8) |\r
-                  ((src & 0x0000FF00) << 8) |\r
-                  ((src & 0x000000FF) << 24);\r
-}\r
-\r
-short _pico_little_short( short src )\r
-{\r
-       return ((src & 0xFF00) >> 8) |\r
-                  ((src & 0x00FF) << 8);\r
-}\r
-\r
-float _pico_little_float( float src )\r
-{\r
-       floatSwapUnion in,out;\r
-       in.f = src;\r
-       out.c[ 0 ] = in.c[ 3 ];\r
-       out.c[ 1 ] = in.c[ 2 ];\r
-       out.c[ 2 ] = in.c[ 1 ];\r
-       out.c[ 3 ] = in.c[ 0 ];\r
-       return out.f;\r
-}\r
-#else /*__BIG_ENDIAN__*/\r
-\r
-int   _pico_little_long ( int   src ) { return src; }\r
-short _pico_little_short( short src ) { return src; }\r
-float _pico_little_float( float src ) { return src; }\r
-       \r
-int _pico_big_long( int src )\r
-{\r
-       return ((src & 0xFF000000) >> 24) |\r
-                  ((src & 0x00FF0000) >> 8) |\r
-                  ((src & 0x0000FF00) << 8) |\r
-                  ((src & 0x000000FF) << 24);\r
-}\r
-       \r
-short _pico_big_short( short src )\r
-{\r
-       return ((src & 0xFF00) >> 8) |\r
-                  ((src & 0x00FF) << 8);\r
-}\r
-       \r
-float _pico_big_float( float src )\r
-{\r
-       floatSwapUnion in,out;\r
-       in.f = src;\r
-       out.c[ 0 ] = in.c[ 3 ];\r
-       out.c[ 1 ] = in.c[ 2 ];\r
-       out.c[ 2 ] = in.c[ 1 ];\r
-       out.c[ 3 ] = in.c[ 0 ];\r
-       return out.f;\r
-}\r
-#endif /*__BIG_ENDIAN__*/\r
-\r
-/* _pico_stristr:\r
- *  case-insensitive strstr. -sea\r
- */\r
-char *_pico_stristr( char *str, const char *substr )\r
-{\r
-       const int sublen = strlen(substr);\r
-       while (*str)\r
-       {\r
-               if (!_pico_strnicmp(str,substr,sublen)) break;\r
-               str++;\r
-       }\r
-       if (!(*str)) str = NULL;\r
-       return str;\r
-}\r
-\r
-/*\r
-_pico_unixify()\r
-changes dos \ style path separators to /\r
-*/\r
-\r
-void _pico_unixify( char *path )\r
-{\r
-       if( path == NULL )\r
-               return;\r
-       while( *path )\r
-       {\r
-               if( *path == '\\' )\r
-                       *path = '/';\r
-               path++;\r
-       }\r
-}\r
-\r
-/* _pico_nofname:\r
- *  removes file name portion from given file path and converts\r
- *  the directory separators to un*x style. returns 1 on success\r
- *  or 0 when 'destSize' was exceeded. -sea\r
- */\r
-int _pico_nofname( const char *path, char *dest, int destSize )\r
-{\r
-       int   left  = destSize;\r
-       char *temp  = dest;\r
-\r
-       while ((*dest = *path) != '\0')\r
-       {\r
-               if (*dest == '/' || *dest == '\\')\r
-               {\r
-                       temp = (dest + 1);\r
-                       *dest = '/';\r
-               }\r
-               dest++; path++;\r
-\r
-               if (--left < 1)\r
-               {\r
-                       *temp = '\0';\r
-                       return 0;\r
-               }\r
-       }\r
-       *temp = '\0';\r
-       return 1;\r
-}\r
-\r
-/* _pico_nopath:\r
- *  returns ptr to filename portion in given path or an empty\r
- *  string otherwise. given 'path' is not altered. -sea\r
- */\r
-char *_pico_nopath( const char *path )\r
-{\r
-       char *src;\r
-       src = (char *)path + (strlen(path) - 1);\r
-\r
-       if (path == NULL) return (char *)"";\r
-       if (!strchr((char *)path,'/') && !strchr((char *)path,'\\'))\r
-               return ((char *)path);\r
-\r
-       while ((src--) != path)\r
-       {\r
-               if (*src == '/' || *src == '\\')\r
-                       return (++src);\r
-       }\r
-       return (char *)"";\r
-}\r
-\r
-/* _pico_setfext:\r
- *  sets/changes the file extension for the given filename\r
- *  or filepath's filename portion. the given 'path' *is*\r
- *  altered. leave 'ext' empty to remove extension. -sea\r
- */\r
-char *_pico_setfext( char *path, const char *ext )\r
-{\r
-       char *src;\r
-       int   remfext = 0;\r
-\r
-       src = path + (strlen(path) - 1);\r
-\r
-       if (ext == NULL) ext = "";\r
-       if (strlen(ext ) < 1) remfext = 1;\r
-       if (strlen(path) < 1)\r
-               return path;\r
-\r
-       while ((src--) != path)\r
-       {\r
-               if (*src == '/' || *src == '\\')\r
-                       return path;\r
-\r
-               if (*src == '.')\r
-               {\r
-                       if (remfext)\r
-                       {\r
-                               *src = '\0';\r
-                               return path;\r
-                       }\r
-                       *(++src) = '\0';\r
-                       break;\r
-               }\r
-       }\r
-       strcat(path,ext);\r
-       return path;\r
-}\r
-\r
-/* _pico_getline:\r
- *  extracts one line from the given buffer and stores it in dest.\r
- *  returns -1 on error or the length of the line on success. i've\r
- *  removed string trimming here. this can be done manually by the\r
- *  calling func.\r
- */\r
-int _pico_getline( char *buf, int bufsize, char *dest, int destsize )\r
-{\r
-       int pos;\r
-\r
-       /* check output */\r
-       if (dest == NULL || destsize < 1) return -1;\r
-       memset( dest,0,destsize );\r
-\r
-       /* check input */\r
-       if (buf == NULL || bufsize < 1)\r
-               return -1;\r
-\r
-       /* get next line */\r
-       for (pos=0; pos<bufsize && pos<destsize; pos++)\r
-       {\r
-               if (buf[pos] == '\n') { pos++; break; }\r
-               dest[pos] = buf[pos];\r
-       }\r
-       /* terminate dest and return */\r
-       dest[pos] = '\0';\r
-       return pos;\r
-}\r
-\r
-/* _pico_parse_skip_white:\r
- *  skips white spaces in current pico parser, sets *hasLFs\r
- *  to 1 if linefeeds were skipped, and either returns the\r
- *  parser's cursor pointer or NULL on error. -sea\r
- */\r
-void _pico_parse_skip_white( picoParser_t *p, int *hasLFs )\r
-{\r
-       /* sanity checks */\r
-       if (p == NULL || p->cursor == NULL)\r
-               return;\r
-\r
-       /* skin white spaces */\r
-       while( 1 )\r
-       {\r
-               /* sanity checks */\r
-               if (p->cursor <  p->buffer ||\r
-                       p->cursor >= p->max)\r
-               {\r
-                       return;\r
-               }\r
-               /* break for chars other than white spaces */\r
-               if (*p->cursor >  0x20) break;\r
-               if (*p->cursor == 0x00) return;\r
-\r
-               /* a bit of linefeed handling */\r
-               if (*p->cursor == '\n')\r
-               {\r
-                       *hasLFs = 1;\r
-                       p->curLine++;\r
-               }\r
-               /* go to next character */\r
-               p->cursor++;\r
-       }\r
-}\r
-\r
-/* _pico_new_parser:\r
- *  allocates a new ascii parser object.\r
- */\r
-picoParser_t *_pico_new_parser( picoByte_t *buffer, int bufSize )\r
-{\r
-       picoParser_t *p;\r
-       \r
-       /* sanity check */\r
-       if( buffer == NULL || bufSize <= 0 )\r
-               return NULL;\r
-       \r
-       /* allocate reader */\r
-       p = _pico_alloc( sizeof(picoParser_t) );\r
-       if (p == NULL) return NULL;\r
-       memset( p,0,sizeof(picoParser_t) );\r
-\r
-       /* allocate token space */\r
-       p->tokenSize = 0;\r
-       p->tokenMax = 1024;\r
-       p->token = _pico_alloc( p->tokenMax );\r
-       if( p->token == NULL )\r
-       {\r
-               _pico_free( p );\r
-               return NULL;\r
-       }\r
-       /* setup */\r
-       p->buffer       = buffer;\r
-       p->cursor       = buffer;\r
-       p->bufSize      = bufSize;\r
-       p->max          = p->buffer + bufSize;\r
-       p->curLine = 1; /* sea: new */\r
-\r
-       /* return ptr to parser */\r
-       return p;\r
-}\r
-\r
-/* _pico_free_parser:\r
- *  frees an existing pico parser object.\r
- */\r
-void _pico_free_parser( picoParser_t *p )\r
-{\r
-       /* sanity check */\r
-       if (p == NULL) return;\r
-\r
-       /* free the parser */\r
-       if (p->token != NULL)\r
-       {\r
-               _pico_free( p->token );\r
-       }\r
-       _pico_free( p );\r
-}\r
-\r
-/* _pico_parse_ex:\r
- *  reads the next token from given pico parser object. if param\r
- * 'allowLFs' is 1 it will read beyond linefeeds and return 0 when\r
- *  the EOF is reached. if 'allowLFs' is 0 it will return 0 when\r
- *  the EOL is reached. if 'handleQuoted' is 1 the parser function\r
- *  will handle "quoted" strings and return the data between the\r
- *  quotes as token. returns 0 on end/error or 1 on success. -sea\r
- */\r
-int _pico_parse_ex( picoParser_t *p, int allowLFs, int handleQuoted )\r
-{\r
-       int hasLFs = 0;\r
-       char *old;\r
-\r
-       /* sanity checks */\r
-       if( p == NULL || p->buffer == NULL ||\r
-               p->cursor <  p->buffer ||\r
-               p->cursor >= p->max )\r
-       {\r
-               return 0;\r
-       }\r
-       /* clear parser token */\r
-       p->tokenSize = 0;\r
-       p->token[ 0 ] = '\0';\r
-       old = p->cursor;\r
-\r
-       /* skip whitespaces */\r
-       while( p->cursor < p->max && *p->cursor <= 32 )\r
-       {\r
-               if (*p->cursor == '\n')\r
-               {\r
-                       p->curLine++;\r
-                       hasLFs++;\r
-               }\r
-               p->cursor++;\r
-       }\r
-       /* return if we're not allowed to go beyond lfs */\r
-       if ((hasLFs > 0) && !allowLFs)\r
-       {\r
-               p->cursor = old;\r
-               return 0;\r
-       }\r
-       /* get next quoted string */\r
-       if (*p->cursor == '\"' && handleQuoted)\r
-       {\r
-               p->cursor++;\r
-               while (p->cursor < p->max && *p->cursor)\r
-               {\r
-                       if (*p->cursor == '\\')\r
-                       {\r
-                               if (*(p->cursor+1) == '"')\r
-                               {\r
-                                       p->cursor++;\r
-                               }\r
-                               p->token[ p->tokenSize++ ] = *p->cursor++;\r
-                               continue;\r
-                       }\r
-                       else if (*p->cursor == '\"')\r
-                       {\r
-                               p->cursor++;\r
-                               break;\r
-                       }\r
-                       else if (*p->cursor == '\n')\r
-                       {\r
-                               p->curLine++;\r
-                       }\r
-                       p->token[ p->tokenSize++ ] = *p->cursor++;\r
-               }\r
-               /* terminate token */\r
-               p->token[ p->tokenSize ] = '\0';\r
-               return 1;\r
-       }\r
-       /* otherwise get next word */\r
-       while( p->cursor < p->max && *p->cursor > 32 )\r
-       {\r
-               if (*p->cursor == '\n')\r
-               {\r
-                       p->curLine++;\r
-               }\r
-               p->token[ p->tokenSize++ ] = *p->cursor++;\r
-       }\r
-       /* terminate token */\r
-       p->token[ p->tokenSize ] = '\0';\r
-       return 1;\r
-}\r
-\r
-/* _pico_parse_first:\r
- *  reads the first token from the next line and returns\r
- *  a pointer to it. returns NULL on EOL or EOF. -sea\r
- */\r
-char *_pico_parse_first( picoParser_t *p )\r
-{\r
-       /* sanity check */\r
-       if (p == NULL) return NULL;\r
-\r
-       /* try to read next token (with lfs & quots) */\r
-       if (!_pico_parse_ex( p,1,1 ))\r
-               return NULL;\r
-\r
-       /* return ptr to the token string */\r
-       return p->token;\r
-}\r
-\r
-/* _pico_parse:\r
- *  reads the next token from the parser and returns a pointer\r
- *  to it. quoted strings are handled as usual. returns NULL\r
- *  on EOL or EOF. -sea\r
- */\r
-char *_pico_parse( picoParser_t *p, int allowLFs )\r
-{\r
-       /* sanity check */\r
-       if (p == NULL) return NULL;\r
-\r
-       /* try to read next token (with quots) */\r
-       if (!_pico_parse_ex( p,allowLFs,1 ))\r
-               return NULL;\r
-\r
-       /* return ptr to the token string */\r
-       return p->token;\r
-}\r
-\r
-/* _pico_parse_skip_rest:\r
- *  skips the rest of the current line in parser.\r
- */\r
-void _pico_parse_skip_rest( picoParser_t *p )\r
-{\r
-       while( _pico_parse_ex( p,0,0 ) ) ;\r
-}\r
-\r
-/* _pico_parse_skip_braced:\r
- *  parses/skips over a braced section. returns 1 on success\r
- *  or 0 on error (when there was no closing bracket and the\r
- *  end of buffer was reached or when the opening bracket was\r
- *  missing).\r
- */\r
-int _pico_parse_skip_braced( picoParser_t *p )\r
-{\r
-       int firstToken = 1;\r
-       int level;\r
-\r
-       /* sanity check */\r
-       if (p == NULL) return 0;\r
-\r
-       /* set the initial level for parsing */\r
-       level = 0;\r
-\r
-       /* skip braced section */\r
-       while( 1 )\r
-       {\r
-               /* read next token (lfs allowed) */\r
-               if (!_pico_parse_ex( p,1,1 ))\r
-               {\r
-                       /* end of parser buffer reached */\r
-                       return 0;\r
-               }\r
-               /* first token must be an opening bracket */\r
-               if (firstToken && p->token[0] != '{')\r
-               {\r
-                       /* opening bracket missing */\r
-                       return 0;\r
-               }\r
-               /* we only check this once */\r
-               firstToken = 0;\r
-\r
-               /* update level */\r
-               if (p->token[1] == '\0')\r
-               {\r
-                       if (p->token[0] == '{') level++;\r
-                       if (p->token[0] == '}') level--;\r
-               }\r
-               /* break if we're back at our starting level */\r
-               if (level == 0) break;\r
-       }\r
-       /* successfully skipped braced section */\r
-       return 1;\r
-}\r
-\r
-int _pico_parse_check( picoParser_t *p, int allowLFs, char *str )\r
-{\r
-       if (!_pico_parse_ex( p,allowLFs,1 ))\r
-               return 0;\r
-       if (!strcmp(p->token,str))\r
-               return 1;\r
-               return 0;\r
-}\r
-\r
-int _pico_parse_checki( picoParser_t *p, int allowLFs, char *str )\r
-{\r
-       if (!_pico_parse_ex( p,allowLFs,1 ))\r
-               return 0;\r
-       if (!_pico_stricmp(p->token,str))\r
-               return 1;\r
-               return 0;\r
-}\r
-\r
-int _pico_parse_int( picoParser_t *p, int *out )\r
-{\r
-       char *token;\r
-\r
-       /* sanity checks */\r
-       if (p == NULL || out == NULL)\r
-               return 0;\r
-\r
-       /* get token and turn it into an integer */\r
-       *out = 0;\r
-       token = _pico_parse( p,0 );\r
-       if (token == NULL) return 0;\r
-       *out = atoi( token );\r
-\r
-       /* success */\r
-       return 1;\r
-}\r
-\r
-int _pico_parse_int_def( picoParser_t *p, int *out, int def )\r
-{\r
-       char *token;\r
-\r
-       /* sanity checks */\r
-       if (p == NULL || out == NULL)\r
-               return 0;\r
-\r
-       /* get token and turn it into an integer */\r
-       *out = def;\r
-       token = _pico_parse( p,0 );\r
-       if (token == NULL) return 0;\r
-       *out = atoi( token );\r
-\r
-       /* success */\r
-       return 1;\r
-}\r
-\r
-int _pico_parse_float( picoParser_t *p, float *out )\r
-{\r
-       char *token;\r
-\r
-       /* sanity checks */\r
-       if (p == NULL || out == NULL)\r
-               return 0;\r
-\r
-       /* get token and turn it into a float */\r
-       *out = 0.0f;\r
-       token = _pico_parse( p,0 );\r
-       if (token == NULL) return 0;\r
-       *out = (float) atof( token );\r
-\r
-       /* success */\r
-       return 1;\r
-}\r
-\r
-int _pico_parse_float_def( picoParser_t *p, float *out, float def )\r
-{\r
-       char *token;\r
-\r
-       /* sanity checks */\r
-       if (p == NULL || out == NULL)\r
-               return 0;\r
-\r
-       /* get token and turn it into a float */\r
-       *out = def;\r
-       token = _pico_parse( p,0 );\r
-       if (token == NULL) return 0;\r
-       *out = (float) atof( token );\r
-\r
-       /* success */\r
-       return 1;\r
-}\r
-\r
-int _pico_parse_vec( picoParser_t *p, picoVec3_t out )\r
-{\r
-       char *token;\r
-       int       i;\r
-\r
-       /* sanity checks */\r
-       if (p == NULL || out == NULL)\r
-               return 0;\r
-\r
-       /* zero out outination vector */\r
-       _pico_zero_vec( out );\r
-\r
-       /* parse three vector components */\r
-       for (i=0; i<3; i++)\r
-       {\r
-               token = _pico_parse( p,0 );\r
-               if (token == NULL)\r
-               {\r
-                       _pico_zero_vec( out );\r
-                       return 0;\r
-               }\r
-               out[ i ] = (float) atof( token );\r
-       }\r
-       /* success */\r
-       return 1;\r
-}\r
-\r
-int _pico_parse_vec_def( picoParser_t *p, picoVec3_t out, picoVec3_t def )\r
-{\r
-       char *token;\r
-       int       i;\r
-\r
-       /* sanity checks */\r
-       if (p == NULL || out == NULL)\r
-               return 0;\r
-\r
-       /* assign default vector value */\r
-       _pico_copy_vec( def,out );\r
-\r
-       /* parse three vector components */\r
-       for (i=0; i<3; i++)\r
-       {\r
-               token = _pico_parse( p,0 );\r
-               if (token == NULL)\r
-               {\r
-                       _pico_copy_vec( def,out );\r
-                       return 0;\r
-               }\r
-               out[ i ] = (float) atof( token );\r
-       }\r
-       /* success */\r
-       return 1;\r
-}\r
-\r
-int _pico_parse_vec2( picoParser_t *p, picoVec2_t out )\r
-{\r
-       char *token;\r
-       int       i;\r
-\r
-       /* sanity checks */\r
-       if (p == NULL || out == NULL)\r
-               return 0;\r
-\r
-       /* zero out outination vector */\r
-       _pico_zero_vec2( out );\r
-\r
-       /* parse two vector components */\r
-       for (i=0; i<2; i++)\r
-       {\r
-               token = _pico_parse( p,0 );\r
-               if (token == NULL)\r
-               {\r
-                       _pico_zero_vec2( out );\r
-                       return 0;\r
-               }\r
-               out[ i ] = (float) atof( token );\r
-       }\r
-       /* success */\r
-       return 1;\r
-}\r
-\r
-int _pico_parse_vec2_def( picoParser_t *p, picoVec2_t out, picoVec2_t def )\r
-{\r
-       char *token;\r
-       int       i;\r
-\r
-       /* sanity checks */\r
-       if (p == NULL || out == NULL)\r
-               return 0;\r
-\r
-       /* assign default vector value */\r
-       _pico_copy_vec2( def,out );\r
-\r
-       /* parse two vector components */\r
-       for (i=0; i<2; i++)\r
-       {\r
-               token = _pico_parse( p,0 );\r
-               if (token == NULL)\r
-               {\r
-                       _pico_copy_vec2( def,out );\r
-                       return 0;\r
-               }\r
-               out[ i ] = (float) atof( token );\r
-       }\r
-       /* success */\r
-       return 1;\r
-}\r
-\r
-int _pico_parse_vec4( picoParser_t *p, picoVec4_t out )\r
-{\r
-       char *token;\r
-       int       i;\r
-\r
-       /* sanity checks */\r
-       if (p == NULL || out == NULL)\r
-               return 0;\r
-\r
-       /* zero out outination vector */\r
-       _pico_zero_vec4( out );\r
-\r
-       /* parse four vector components */\r
-       for (i=0; i<4; i++)\r
-       {\r
-               token = _pico_parse( p,0 );\r
-               if (token == NULL)\r
-               {\r
-                       _pico_zero_vec4( out );\r
-                       return 0;\r
-               }\r
-               out[ i ] = (float) atof( token );\r
-       }\r
-       /* success */\r
-       return 1;\r
-}\r
-\r
-int _pico_parse_vec4_def( picoParser_t *p, picoVec4_t out, picoVec4_t def )\r
-{\r
-       char *token;\r
-       int       i;\r
-\r
-       /* sanity checks */\r
-       if (p == NULL || out == NULL)\r
-               return 0;\r
-\r
-       /* assign default vector value */\r
-       _pico_copy_vec4( def,out );\r
-\r
-       /* parse four vector components */\r
-       for (i=0; i<4; i++)\r
-       {\r
-               token = _pico_parse( p,0 );\r
-               if (token == NULL)\r
-               {\r
-                       _pico_copy_vec4( def,out );\r
-                       return 0;\r
-               }\r
-               out[ i ] = (float) atof( token );\r
-       }\r
-       /* success */\r
-       return 1;\r
-}\r
-\r
-/* _pico_new_memstream:\r
- *  allocates a new memorystream object.\r
- */\r
-picoMemStream_t *_pico_new_memstream( picoByte_t *buffer, int bufSize )\r
-{\r
-       picoMemStream_t *s;\r
-       \r
-       /* sanity check */\r
-       if( buffer == NULL || bufSize <= 0 )\r
-               return NULL;\r
-       \r
-       /* allocate stream */\r
-       s = _pico_alloc( sizeof(picoMemStream_t) );\r
-       if (s == NULL) return NULL;\r
-       memset( s,0,sizeof(picoMemStream_t) );\r
-\r
-       /* setup */\r
-       s->buffer       = buffer;\r
-       s->curPos       = buffer;\r
-       s->bufSize      = bufSize;\r
-       s->flag         = 0;\r
-\r
-       /* return ptr to stream */\r
-       return s;\r
-}\r
-\r
-/* _pico_free_memstream:\r
- *  frees an existing pico memorystream object.\r
- */\r
-void _pico_free_memstream( picoMemStream_t *s )\r
-{\r
-       /* sanity check */\r
-       if (s == NULL) return;\r
-\r
-       /* free the stream */\r
-       _pico_free( s );\r
-}\r
-\r
-/* _pico_memstream_read:\r
- *  reads data from a pico memorystream into a buffer.\r
- */\r
-int _pico_memstream_read( picoMemStream_t *s, void *buffer, int len )\r
-{\r
-       int ret = 1;\r
-\r
-       /* sanity checks */\r
-       if (s == NULL || buffer == NULL)\r
-               return 0;\r
-\r
-       if (s->curPos + len > s->buffer + s->bufSize)\r
-       {\r
-               s->flag |= PICO_IOEOF;\r
-               len = s->buffer + s->bufSize - s->curPos;\r
-               ret = 0;\r
-       }\r
-\r
-       /* read the data */\r
-       memcpy( buffer, s->curPos, len );\r
-       s->curPos += len;\r
-       return ret;\r
-}\r
-\r
-/* _pico_memstream_read:\r
- *  reads a character from a pico memorystream\r
- */\r
-int _pico_memstream_getc( picoMemStream_t *s )\r
-{\r
-       int c = 0;\r
-\r
-       /* sanity check */\r
-       if (s == NULL)\r
-               return -1;\r
-\r
-       /* read the character */\r
-       if (_pico_memstream_read( s, &c, 1) == 0)\r
-               return -1;\r
-\r
-       return c;\r
-}\r
-\r
-/* _pico_memstream_seek:\r
- *  sets the current read position to a different location\r
- */\r
-int _pico_memstream_seek( picoMemStream_t *s, long offset, int origin )\r
-{\r
-       int overflow;\r
-\r
-       /* sanity check */\r
-       if (s == NULL)\r
-               return -1;\r
-\r
-       if (origin == PICO_SEEK_SET)\r
-       {\r
-               s->curPos = s->buffer + offset;\r
-               overflow = s->curPos - ( s->buffer + s->bufSize );\r
-               if (overflow > 0)\r
-               {\r
-                       s->curPos = s->buffer + s->bufSize;\r
-                       return offset - overflow;\r
-               }\r
-               return 0;\r
-       }\r
-       else if (origin == PICO_SEEK_CUR)\r
-       {\r
-               s->curPos += offset;\r
-               overflow = s->curPos - ( s->buffer + s->bufSize );\r
-               if (overflow > 0)\r
-               {\r
-                       s->curPos = s->buffer + s->bufSize;\r
-                       return offset - overflow;\r
-               }\r
-               return 0;\r
-       }\r
-       else if (origin == PICO_SEEK_END)\r
-       {\r
-               s->curPos = ( s->buffer + s->bufSize ) - offset;\r
-               overflow = s->buffer - s->curPos;\r
-               if (overflow > 0)\r
-               {\r
-                       s->curPos = s->buffer;\r
-                       return offset - overflow;\r
-               }\r
-               return 0;\r
-       }\r
-\r
-       return -1;\r
-}\r
-\r
-/* _pico_memstream_tell:\r
- *  returns the current read position in the pico memorystream\r
- */\r
-long _pico_memstream_tell( picoMemStream_t *s )\r
-{\r
-       /* sanity check */\r
-       if (s == NULL)\r
-               return -1;\r
-\r
-       return s->curPos - s->buffer;\r
-}\r
+/* -----------------------------------------------------------------------------
+
+PicoModel Library
+
+Copyright (c) 2002, Randy Reddig & seaw0lf
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+Neither the names of the copyright holders nor the names of its contributors may
+be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------------- */
+
+
+
+/* marker */
+#define PICOINTERNAL_C
+
+
+
+/* todo:
+ * - fix p->curLine for parser routines. increased twice
+ */
+
+/* dependencies */
+#include <string.h>
+#include "picointernal.h"
+
+
+
+/* function pointers */
+void *(*_pico_ptr_malloc       )( size_t ) = malloc;
+void  (*_pico_ptr_free         )( void* ) = free;
+void  (*_pico_ptr_load_file    )( char*, unsigned char**, int* ) = NULL;
+void  (*_pico_ptr_free_file    )( void* ) = NULL;
+void  (*_pico_ptr_print                )( int, const char* ) = NULL;
+
+typedef union
+{
+       float   f;
+       char    c[4];
+}
+floatSwapUnion;
+
+/* _pico_alloc:
+ *  kludged memory allocation wrapper
+ */
+void *_pico_alloc( size_t size )
+{
+       void *ptr;
+
+       /* some sanity checks */
+       if( size == 0 )
+               return NULL;
+       if (_pico_ptr_malloc == NULL)
+               return NULL;
+
+       /* allocate memory */
+       ptr = _pico_ptr_malloc(size);
+       if (ptr == NULL)
+               return NULL;
+
+       /* zero out allocated memory */
+       memset(ptr,0,size);
+
+       /* return pointer to allocated memory */
+       return ptr;
+}
+
+/* _pico_calloc:
+ *  _pico_calloc wrapper
+ */
+void *_pico_calloc( size_t num, size_t size )
+{
+       void *ptr;
+
+       /* some sanity checks */
+       if( num == 0 || size == 0 )
+               return NULL;
+       if (_pico_ptr_malloc == NULL)
+               return NULL;
+
+       /* allocate memory */
+       ptr = _pico_ptr_malloc(num*size);
+       if (ptr == NULL)
+               return NULL;
+
+       /* zero out allocated memory */
+       memset(ptr,0,num*size);
+
+       /* return pointer to allocated memory */
+       return ptr;
+}
+
+/* _pico_realloc:
+ *  memory reallocation wrapper (note: only grows,
+ *  but never shrinks or frees)
+ */
+void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize )
+{
+       void *ptr2;
+       
+       /* sanity checks */
+       if( ptr == NULL )
+               return NULL;
+       if( newSize < oldSize )
+               return *ptr;
+       if (_pico_ptr_malloc == NULL)
+               return NULL;
+
+       /* allocate new pointer */
+       ptr2 = _pico_alloc( newSize );
+       if( ptr2 == NULL )
+               return NULL;
+
+       /* copy */
+       if( *ptr != NULL )
+       {
+               memcpy( ptr2, *ptr, oldSize );
+               _pico_free( *ptr );
+       }
+       
+       /* fix up and return */
+       *ptr = ptr2;
+       return *ptr;
+}
+
+/* _pico_clone_alloc:
+ *  handy function for quick string allocation/copy. it clones
+ *  the given string and returns a pointer to the new allocated
+ *  clone (which must be freed by caller of course) or returns
+ *  NULL on memory alloc or param errors. if 'size' is -1 the
+ *  length of the input string is used, otherwise 'size' is used
+ *  as custom clone size (the string is cropped to fit into mem
+ *  if needed). -sea
+ */
+char *_pico_clone_alloc( char *str, int size )
+{
+       char  *cloned;
+       size_t cloneSize;
+
+       /* sanity check */
+       if (str == NULL) return NULL;
+
+       /* set real size of cloned string */
+       cloneSize = (size < 0) ? strlen(str) : size;
+
+       /* allocate memory */
+       cloned = _pico_alloc( cloneSize+1 ); /* bugfix! */
+       if (cloned == NULL)
+               return NULL;
+
+       /* zero out memory allocated by cloned string */
+       memset( cloned,0,cloneSize );
+
+       /* copy input string to cloned string */
+       if (cloneSize < strlen( str )) {
+               memcpy( cloned,str,cloneSize );
+               cloned[ cloneSize ] = '\0';
+       } else {
+               strcpy( cloned,str );
+       }
+       /* return ptr to cloned string */
+       return cloned;
+}
+
+/* _pico_free:
+ * wrapper around the free function pointer
+ */
+void _pico_free( void *ptr )
+{
+       /* sanity checks */
+       if( ptr == NULL )
+               return;
+       if (_pico_ptr_free == NULL)
+               return;
+
+       /* free the allocated memory */
+               _pico_ptr_free( ptr );
+}
+
+/* _pico_load_file:
+ * wrapper around the loadfile function pointer
+ */
+void _pico_load_file( char *name, unsigned char **buffer, int *bufSize )
+{
+       /* sanity checks */
+       if( name == NULL )
+       {
+               *bufSize = -1;
+               return;
+       }
+       if (_pico_ptr_load_file == NULL)
+       {
+               *bufSize = -1;
+               return;
+       }
+       /* do the actual call to read in the file; */
+       /* BUFFER IS ALLOCATED BY THE EXTERNAL LOADFILE FUNC */
+       _pico_ptr_load_file( name,buffer,bufSize );
+}
+
+/* _pico_free_file:
+ * wrapper around the file free function pointer
+ */
+void _pico_free_file( void *buffer )
+{
+       /* sanity checks */
+       if( buffer == NULL )
+               return;
+
+       /* use default free */
+       if( _pico_ptr_free_file == NULL )
+       {
+               free( buffer );
+               return;
+       }
+       /* free the allocated file */
+       _pico_ptr_free_file( buffer );
+}
+
+/* _pico_printf:
+ * wrapper around the print function pointer -sea
+ */
+void _pico_printf( int level, const char *format, ...)
+{
+       char    str[4096];
+       va_list argptr;
+
+       /* sanity checks */
+       if( format == NULL )
+               return;
+       if (_pico_ptr_print == NULL)
+               return;
+
+       /* format string */
+       va_start( argptr,format );
+       vsprintf( str,format,argptr );
+       va_end( argptr );
+
+       /* remove linefeeds */
+       if (str[ strlen(str)-1 ] == '\n')
+               str[ strlen(str)-1 ] = '\0';
+
+       /* do the actual call */
+       _pico_ptr_print( level,str );
+}
+
+/* _pico_strltrim:
+ *   left trims the given string -sea
+ */
+char *_pico_strltrim( char *str )
+{
+       char *str1 = str, *str2 = str;
+
+       while (isspace(*str2)) str2++;
+       if( str2 != str )
+               while( *str2 != '\0' ) /* fix: ydnar */
+                       *str1++ = *str2++;
+       return str;
+}
+
+/* _pico_strrtrim:
+ *   right trims the given string -sea
+ */
+char *_pico_strrtrim( char *str )
+{
+       if (str && *str)
+       {
+               char *str1 = str;
+               int allspace = 1;
+
+               while (*str1)
+               {
+                       if (allspace && !isspace(*str1)) allspace = 0;
+                       str1++;
+               }
+               if (allspace) *str = '\0';
+               else {
+                       str1--;
+                       while ((isspace(*str1)) && (str1 >= str))
+                               *str1-- = '\0';
+               }
+       }
+    return str;
+}
+
+/* _pico_strlwr:
+ *  pico internal string-to-lower routine.
+ */
+char *_pico_strlwr( char *str )
+{
+       char *cp;
+       for (cp=str; *cp; ++cp)
+       {
+               if ('A' <= *cp && *cp <= 'Z')
+               {
+                       *cp += ('a' - 'A');
+               }
+       }
+       return str;
+}
+
+/* _pico_strchcount:
+ *  counts how often the given char appears in str. -sea
+ */
+int _pico_strchcount( char *str, int ch )
+{
+       int count = 0;
+       while (*str++) if (*str == ch) count++;
+       return count;
+}
+
+void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs )
+{
+       int i;
+       for (i=0; i<3; i++)
+       {
+               mins[i] = +999999;
+               maxs[i] = -999999;
+       }
+}
+
+void _pico_expand_bounds( picoVec3_t p, picoVec3_t mins, picoVec3_t maxs )
+{
+       int i;
+       for (i=0; i<3; i++)
+       {
+               float value = p[i];
+               if (value < mins[i]) mins[i] = value;
+               if (value > maxs[i]) maxs[i] = value;
+       }
+}
+
+void _pico_zero_vec( picoVec3_t vec )
+{
+       vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = 0;
+}
+
+void _pico_zero_vec2( picoVec2_t vec )
+{
+       vec[ 0 ] = vec[ 1 ] = 0;
+}
+
+void _pico_zero_vec4( picoVec4_t vec )
+{
+       vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = vec[ 3 ] = 0;
+}
+
+void _pico_set_vec( picoVec3_t v, float a, float b, float c )
+{
+       v[ 0 ] = a;
+       v[ 1 ] = b;
+       v[ 2 ] = c;
+}
+
+void _pico_set_vec4( picoVec4_t v, float a, float b, float c, float d )
+{
+       v[ 0 ] = a;
+       v[ 1 ] = b;
+       v[ 2 ] = c;
+       v[ 3 ] = d;
+}
+
+void _pico_copy_vec( picoVec3_t src, picoVec3_t dest )
+{
+       dest[ 0 ] = src[ 0 ];
+       dest[ 1 ] = src[ 1 ];
+       dest[ 2 ] = src[ 2 ];
+}
+
+void _pico_copy_vec2( picoVec2_t src, picoVec2_t dest )
+{
+       dest[ 0 ] = src[ 0 ];
+       dest[ 1 ] = src[ 1 ];
+}
+
+void _pico_copy_vec4( picoVec4_t src, picoVec4_t dest )
+{
+       dest[ 0 ] = src[ 0 ];
+       dest[ 1 ] = src[ 1 ];
+       dest[ 2 ] = src[ 2 ];
+       dest[ 3 ] = src[ 3 ];
+}
+
+/* ydnar */
+picoVec_t _pico_normalize_vec( picoVec3_t vec )
+{
+       double  len, ilen;
+       
+       len = sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] + vec[ 2 ] * vec[ 2 ] );
+       if( len == 0.0 ) return 0.0;
+       ilen = 1.0 / len;
+       vec[ 0 ] *= (picoVec_t) ilen;
+       vec[ 1 ] *= (picoVec_t) ilen;
+       vec[ 2 ] *= (picoVec_t) ilen;
+       return (picoVec_t) len;
+}
+
+void _pico_add_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest )
+{
+       dest[ 0 ] = a[ 0 ] + b[ 0 ];
+       dest[ 1 ] = a[ 1 ] + b[ 1 ];
+       dest[ 2 ] = a[ 2 ] + b[ 2 ];
+}
+
+void _pico_subtract_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest )
+{
+       dest[ 0 ] = a[ 0 ] - b[ 0 ];
+       dest[ 1 ] = a[ 1 ] - b[ 1 ];
+       dest[ 2 ] = a[ 2 ] - b[ 2 ];
+}
+
+void _pico_scale_vec( picoVec3_t v, float scale, picoVec3_t dest )
+{
+       dest[ 0 ] = v[ 0 ] * scale;
+       dest[ 1 ] = v[ 1 ] * scale;
+       dest[ 2 ] = v[ 2 ] * scale;
+}
+
+void _pico_scale_vec4( picoVec4_t v, float scale, picoVec4_t dest )
+{
+       dest[ 0 ] = v[ 0 ] * scale;
+       dest[ 1 ] = v[ 1 ] * scale;
+       dest[ 2 ] = v[ 2 ] * scale;
+       dest[ 3 ] = v[ 3 ] * scale;
+}
+
+picoVec_t _pico_dot_vec( picoVec3_t a, picoVec3_t b )
+{
+       return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ];
+}
+
+void _pico_cross_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest )
+{
+       dest[ 0 ] = a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ];
+       dest[ 1 ] = a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ];
+       dest[ 2 ] = a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ];
+}
+
+picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVec3_t c )
+{
+       picoVec3_t      ba, ca;
+
+       _pico_subtract_vec( b, a, ba );
+       _pico_subtract_vec( c, a, ca );
+       _pico_cross_vec( ca, ba, plane );
+       plane[ 3 ] = _pico_dot_vec( a, plane );
+       return _pico_normalize_vec( plane );
+}
+
+/* separate from _pico_set_vec4 */
+void _pico_set_color( picoColor_t c, int r, int g, int b, int a )
+{
+       c[ 0 ] = r;
+       c[ 1 ] = g;
+       c[ 2 ] = b;
+       c[ 3 ] = a;
+}
+
+void _pico_copy_color( picoColor_t src, picoColor_t dest )
+{
+       dest[ 0 ] = src[ 0 ];
+       dest[ 1 ] = src[ 1 ];
+       dest[ 2 ] = src[ 2 ];
+       dest[ 3 ] = src[ 3 ];
+}
+
+#ifdef __BIG_ENDIAN__
+
+int   _pico_big_long ( int   src ) { return src; }
+short _pico_big_short( short src ) { return src; }
+float _pico_big_float( float src ) { return src; }
+
+int _pico_little_long( int src )
+{
+       return ((src & 0xFF000000) >> 24) |
+                  ((src & 0x00FF0000) >> 8) |
+                  ((src & 0x0000FF00) << 8) |
+                  ((src & 0x000000FF) << 24);
+}
+
+short _pico_little_short( short src )
+{
+       return ((src & 0xFF00) >> 8) |
+                  ((src & 0x00FF) << 8);
+}
+
+float _pico_little_float( float src )
+{
+       floatSwapUnion in,out;
+       in.f = src;
+       out.c[ 0 ] = in.c[ 3 ];
+       out.c[ 1 ] = in.c[ 2 ];
+       out.c[ 2 ] = in.c[ 1 ];
+       out.c[ 3 ] = in.c[ 0 ];
+       return out.f;
+}
+#else /*__BIG_ENDIAN__*/
+
+int   _pico_little_long ( int   src ) { return src; }
+short _pico_little_short( short src ) { return src; }
+float _pico_little_float( float src ) { return src; }
+       
+int _pico_big_long( int src )
+{
+       return ((src & 0xFF000000) >> 24) |
+                  ((src & 0x00FF0000) >> 8) |
+                  ((src & 0x0000FF00) << 8) |
+                  ((src & 0x000000FF) << 24);
+}
+       
+short _pico_big_short( short src )
+{
+       return ((src & 0xFF00) >> 8) |
+                  ((src & 0x00FF) << 8);
+}
+       
+float _pico_big_float( float src )
+{
+       floatSwapUnion in,out;
+       in.f = src;
+       out.c[ 0 ] = in.c[ 3 ];
+       out.c[ 1 ] = in.c[ 2 ];
+       out.c[ 2 ] = in.c[ 1 ];
+       out.c[ 3 ] = in.c[ 0 ];
+       return out.f;
+}
+#endif /*__BIG_ENDIAN__*/
+
+/* _pico_stristr:
+ *  case-insensitive strstr. -sea
+ */
+char *_pico_stristr( char *str, const char *substr )
+{
+       const int sublen = strlen(substr);
+       while (*str)
+       {
+               if (!_pico_strnicmp(str,substr,sublen)) break;
+               str++;
+       }
+       if (!(*str)) str = NULL;
+       return str;
+}
+
+/*
+_pico_unixify()
+changes dos \ style path separators to /
+*/
+
+void _pico_unixify( char *path )
+{
+       if( path == NULL )
+               return;
+       while( *path )
+       {
+               if( *path == '\\' )
+                       *path = '/';
+               path++;
+       }
+}
+
+/* _pico_nofname:
+ *  removes file name portion from given file path and converts
+ *  the directory separators to un*x style. returns 1 on success
+ *  or 0 when 'destSize' was exceeded. -sea
+ */
+int _pico_nofname( const char *path, char *dest, int destSize )
+{
+       int   left  = destSize;
+       char *temp  = dest;
+
+       while ((*dest = *path) != '\0')
+       {
+               if (*dest == '/' || *dest == '\\')
+               {
+                       temp = (dest + 1);
+                       *dest = '/';
+               }
+               dest++; path++;
+
+               if (--left < 1)
+               {
+                       *temp = '\0';
+                       return 0;
+               }
+       }
+       *temp = '\0';
+       return 1;
+}
+
+/* _pico_nopath:
+ *  returns ptr to filename portion in given path or an empty
+ *  string otherwise. given 'path' is not altered. -sea
+ */
+char *_pico_nopath( const char *path )
+{
+       char *src;
+       src = (char *)path + (strlen(path) - 1);
+
+       if (path == NULL) return (char *)"";
+       if (!strchr((char *)path,'/') && !strchr((char *)path,'\\'))
+               return ((char *)path);
+
+       while ((src--) != path)
+       {
+               if (*src == '/' || *src == '\\')
+                       return (++src);
+       }
+       return (char *)"";
+}
+
+/* _pico_setfext:
+ *  sets/changes the file extension for the given filename
+ *  or filepath's filename portion. the given 'path' *is*
+ *  altered. leave 'ext' empty to remove extension. -sea
+ */
+char *_pico_setfext( char *path, const char *ext )
+{
+       char *src;
+       int   remfext = 0;
+
+       src = path + (strlen(path) - 1);
+
+       if (ext == NULL) ext = "";
+       if (strlen(ext ) < 1) remfext = 1;
+       if (strlen(path) < 1)
+               return path;
+
+       while ((src--) != path)
+       {
+               if (*src == '/' || *src == '\\')
+                       return path;
+
+               if (*src == '.')
+               {
+                       if (remfext)
+                       {
+                               *src = '\0';
+                               return path;
+                       }
+                       *(++src) = '\0';
+                       break;
+               }
+       }
+       strcat(path,ext);
+       return path;
+}
+
+/* _pico_getline:
+ *  extracts one line from the given buffer and stores it in dest.
+ *  returns -1 on error or the length of the line on success. i've
+ *  removed string trimming here. this can be done manually by the
+ *  calling func.
+ */
+int _pico_getline( char *buf, int bufsize, char *dest, int destsize )
+{
+       int pos;
+
+       /* check output */
+       if (dest == NULL || destsize < 1) return -1;
+       memset( dest,0,destsize );
+
+       /* check input */
+       if (buf == NULL || bufsize < 1)
+               return -1;
+
+       /* get next line */
+       for (pos=0; pos<bufsize && pos<destsize; pos++)
+       {
+               if (buf[pos] == '\n') { pos++; break; }
+               dest[pos] = buf[pos];
+       }
+       /* terminate dest and return */
+       dest[pos] = '\0';
+       return pos;
+}
+
+/* _pico_parse_skip_white:
+ *  skips white spaces in current pico parser, sets *hasLFs
+ *  to 1 if linefeeds were skipped, and either returns the
+ *  parser's cursor pointer or NULL on error. -sea
+ */
+void _pico_parse_skip_white( picoParser_t *p, int *hasLFs )
+{
+       /* sanity checks */
+       if (p == NULL || p->cursor == NULL)
+               return;
+
+       /* skin white spaces */
+       while( 1 )
+       {
+               /* sanity checks */
+               if (p->cursor <  p->buffer ||
+                       p->cursor >= p->max)
+               {
+                       return;
+               }
+               /* break for chars other than white spaces */
+               if (*p->cursor >  0x20) break;
+               if (*p->cursor == 0x00) return;
+
+               /* a bit of linefeed handling */
+               if (*p->cursor == '\n')
+               {
+                       *hasLFs = 1;
+                       p->curLine++;
+               }
+               /* go to next character */
+               p->cursor++;
+       }
+}
+
+/* _pico_new_parser:
+ *  allocates a new ascii parser object.
+ */
+picoParser_t *_pico_new_parser( picoByte_t *buffer, int bufSize )
+{
+       picoParser_t *p;
+       
+       /* sanity check */
+       if( buffer == NULL || bufSize <= 0 )
+               return NULL;
+       
+       /* allocate reader */
+       p = _pico_alloc( sizeof(picoParser_t) );
+       if (p == NULL) return NULL;
+       memset( p,0,sizeof(picoParser_t) );
+
+       /* allocate token space */
+       p->tokenSize = 0;
+       p->tokenMax = 1024;
+       p->token = _pico_alloc( p->tokenMax );
+       if( p->token == NULL )
+       {
+               _pico_free( p );
+               return NULL;
+       }
+       /* setup */
+       p->buffer       = buffer;
+       p->cursor       = buffer;
+       p->bufSize      = bufSize;
+       p->max          = p->buffer + bufSize;
+       p->curLine = 1; /* sea: new */
+
+       /* return ptr to parser */
+       return p;
+}
+
+/* _pico_free_parser:
+ *  frees an existing pico parser object.
+ */
+void _pico_free_parser( picoParser_t *p )
+{
+       /* sanity check */
+       if (p == NULL) return;
+
+       /* free the parser */
+       if (p->token != NULL)
+       {
+               _pico_free( p->token );
+       }
+       _pico_free( p );
+}
+
+/* _pico_parse_ex:
+ *  reads the next token from given pico parser object. if param
+ * 'allowLFs' is 1 it will read beyond linefeeds and return 0 when
+ *  the EOF is reached. if 'allowLFs' is 0 it will return 0 when
+ *  the EOL is reached. if 'handleQuoted' is 1 the parser function
+ *  will handle "quoted" strings and return the data between the
+ *  quotes as token. returns 0 on end/error or 1 on success. -sea
+ */
+int _pico_parse_ex( picoParser_t *p, int allowLFs, int handleQuoted )
+{
+       int hasLFs = 0;
+       char *old;
+
+       /* sanity checks */
+       if( p == NULL || p->buffer == NULL ||
+               p->cursor <  p->buffer ||
+               p->cursor >= p->max )
+       {
+               return 0;
+       }
+       /* clear parser token */
+       p->tokenSize = 0;
+       p->token[ 0 ] = '\0';
+       old = p->cursor;
+
+       /* skip whitespaces */
+       while( p->cursor < p->max && *p->cursor <= 32 )
+       {
+               if (*p->cursor == '\n')
+               {
+                       p->curLine++;
+                       hasLFs++;
+               }
+               p->cursor++;
+       }
+       /* return if we're not allowed to go beyond lfs */
+       if ((hasLFs > 0) && !allowLFs)
+       {
+               p->cursor = old;
+               return 0;
+       }
+       /* get next quoted string */
+       if (*p->cursor == '\"' && handleQuoted)
+       {
+               p->cursor++;
+               while (p->cursor < p->max && *p->cursor)
+               {
+                       if (*p->cursor == '\\')
+                       {
+                               if (*(p->cursor+1) == '"')
+                               {
+                                       p->cursor++;
+                               }
+                               p->token[ p->tokenSize++ ] = *p->cursor++;
+                               continue;
+                       }
+                       else if (*p->cursor == '\"')
+                       {
+                               p->cursor++;
+                               break;
+                       }
+                       else if (*p->cursor == '\n')
+                       {
+                               p->curLine++;
+                       }
+                       p->token[ p->tokenSize++ ] = *p->cursor++;
+               }
+               /* terminate token */
+               p->token[ p->tokenSize ] = '\0';
+               return 1;
+       }
+       /* otherwise get next word */
+       while( p->cursor < p->max && *p->cursor > 32 )
+       {
+               if (*p->cursor == '\n')
+               {
+                       p->curLine++;
+               }
+               p->token[ p->tokenSize++ ] = *p->cursor++;
+       }
+       /* terminate token */
+       p->token[ p->tokenSize ] = '\0';
+       return 1;
+}
+
+/* _pico_parse_first:
+ *  reads the first token from the next line and returns
+ *  a pointer to it. returns NULL on EOL or EOF. -sea
+ */
+char *_pico_parse_first( picoParser_t *p )
+{
+       /* sanity check */
+       if (p == NULL) return NULL;
+
+       /* try to read next token (with lfs & quots) */
+       if (!_pico_parse_ex( p,1,1 ))
+               return NULL;
+
+       /* return ptr to the token string */
+       return p->token;
+}
+
+/* _pico_parse:
+ *  reads the next token from the parser and returns a pointer
+ *  to it. quoted strings are handled as usual. returns NULL
+ *  on EOL or EOF. -sea
+ */
+char *_pico_parse( picoParser_t *p, int allowLFs )
+{
+       /* sanity check */
+       if (p == NULL) return NULL;
+
+       /* try to read next token (with quots) */
+       if (!_pico_parse_ex( p,allowLFs,1 ))
+               return NULL;
+
+       /* return ptr to the token string */
+       return p->token;
+}
+
+/* _pico_parse_skip_rest:
+ *  skips the rest of the current line in parser.
+ */
+void _pico_parse_skip_rest( picoParser_t *p )
+{
+       while( _pico_parse_ex( p,0,0 ) ) ;
+}
+
+/* _pico_parse_skip_braced:
+ *  parses/skips over a braced section. returns 1 on success
+ *  or 0 on error (when there was no closing bracket and the
+ *  end of buffer was reached or when the opening bracket was
+ *  missing).
+ */
+int _pico_parse_skip_braced( picoParser_t *p )
+{
+       int firstToken = 1;
+       int level;
+
+       /* sanity check */
+       if (p == NULL) return 0;
+
+       /* set the initial level for parsing */
+       level = 0;
+
+       /* skip braced section */
+       while( 1 )
+       {
+               /* read next token (lfs allowed) */
+               if (!_pico_parse_ex( p,1,1 ))
+               {
+                       /* end of parser buffer reached */
+                       return 0;
+               }
+               /* first token must be an opening bracket */
+               if (firstToken && p->token[0] != '{')
+               {
+                       /* opening bracket missing */
+                       return 0;
+               }
+               /* we only check this once */
+               firstToken = 0;
+
+               /* update level */
+               if (p->token[1] == '\0')
+               {
+                       if (p->token[0] == '{') level++;
+                       if (p->token[0] == '}') level--;
+               }
+               /* break if we're back at our starting level */
+               if (level == 0) break;
+       }
+       /* successfully skipped braced section */
+       return 1;
+}
+
+int _pico_parse_check( picoParser_t *p, int allowLFs, char *str )
+{
+       if (!_pico_parse_ex( p,allowLFs,1 ))
+               return 0;
+       if (!strcmp(p->token,str))
+               return 1;
+               return 0;
+}
+
+int _pico_parse_checki( picoParser_t *p, int allowLFs, char *str )
+{
+       if (!_pico_parse_ex( p,allowLFs,1 ))
+               return 0;
+       if (!_pico_stricmp(p->token,str))
+               return 1;
+               return 0;
+}
+
+int _pico_parse_int( picoParser_t *p, int *out )
+{
+       char *token;
+
+       /* sanity checks */
+       if (p == NULL || out == NULL)
+               return 0;
+
+       /* get token and turn it into an integer */
+       *out = 0;
+       token = _pico_parse( p,0 );
+       if (token == NULL) return 0;
+       *out = atoi( token );
+
+       /* success */
+       return 1;
+}
+
+int _pico_parse_int_def( picoParser_t *p, int *out, int def )
+{
+       char *token;
+
+       /* sanity checks */
+       if (p == NULL || out == NULL)
+               return 0;
+
+       /* get token and turn it into an integer */
+       *out = def;
+       token = _pico_parse( p,0 );
+       if (token == NULL) return 0;
+       *out = atoi( token );
+
+       /* success */
+       return 1;
+}
+
+int _pico_parse_float( picoParser_t *p, float *out )
+{
+       char *token;
+
+       /* sanity checks */
+       if (p == NULL || out == NULL)
+               return 0;
+
+       /* get token and turn it into a float */
+       *out = 0.0f;
+       token = _pico_parse( p,0 );
+       if (token == NULL) return 0;
+       *out = (float) atof( token );
+
+       /* success */
+       return 1;
+}
+
+int _pico_parse_float_def( picoParser_t *p, float *out, float def )
+{
+       char *token;
+
+       /* sanity checks */
+       if (p == NULL || out == NULL)
+               return 0;
+
+       /* get token and turn it into a float */
+       *out = def;
+       token = _pico_parse( p,0 );
+       if (token == NULL) return 0;
+       *out = (float) atof( token );
+
+       /* success */
+       return 1;
+}
+
+int _pico_parse_vec( picoParser_t *p, picoVec3_t out )
+{
+       char *token;
+       int       i;
+
+       /* sanity checks */
+       if (p == NULL || out == NULL)
+               return 0;
+
+       /* zero out outination vector */
+       _pico_zero_vec( out );
+
+       /* parse three vector components */
+       for (i=0; i<3; i++)
+       {
+               token = _pico_parse( p,0 );
+               if (token == NULL)
+               {
+                       _pico_zero_vec( out );
+                       return 0;
+               }
+               out[ i ] = (float) atof( token );
+       }
+       /* success */
+       return 1;
+}
+
+int _pico_parse_vec_def( picoParser_t *p, picoVec3_t out, picoVec3_t def )
+{
+       char *token;
+       int       i;
+
+       /* sanity checks */
+       if (p == NULL || out == NULL)
+               return 0;
+
+       /* assign default vector value */
+       _pico_copy_vec( def,out );
+
+       /* parse three vector components */
+       for (i=0; i<3; i++)
+       {
+               token = _pico_parse( p,0 );
+               if (token == NULL)
+               {
+                       _pico_copy_vec( def,out );
+                       return 0;
+               }
+               out[ i ] = (float) atof( token );
+       }
+       /* success */
+       return 1;
+}
+
+int _pico_parse_vec2( picoParser_t *p, picoVec2_t out )
+{
+       char *token;
+       int       i;
+
+       /* sanity checks */
+       if (p == NULL || out == NULL)
+               return 0;
+
+       /* zero out outination vector */
+       _pico_zero_vec2( out );
+
+       /* parse two vector components */
+       for (i=0; i<2; i++)
+       {
+               token = _pico_parse( p,0 );
+               if (token == NULL)
+               {
+                       _pico_zero_vec2( out );
+                       return 0;
+               }
+               out[ i ] = (float) atof( token );
+       }
+       /* success */
+       return 1;
+}
+
+int _pico_parse_vec2_def( picoParser_t *p, picoVec2_t out, picoVec2_t def )
+{
+       char *token;
+       int       i;
+
+       /* sanity checks */
+       if (p == NULL || out == NULL)
+               return 0;
+
+       /* assign default vector value */
+       _pico_copy_vec2( def,out );
+
+       /* parse two vector components */
+       for (i=0; i<2; i++)
+       {
+               token = _pico_parse( p,0 );
+               if (token == NULL)
+               {
+                       _pico_copy_vec2( def,out );
+                       return 0;
+               }
+               out[ i ] = (float) atof( token );
+       }
+       /* success */
+       return 1;
+}
+
+int _pico_parse_vec4( picoParser_t *p, picoVec4_t out )
+{
+       char *token;
+       int       i;
+
+       /* sanity checks */
+       if (p == NULL || out == NULL)
+               return 0;
+
+       /* zero out outination vector */
+       _pico_zero_vec4( out );
+
+       /* parse four vector components */
+       for (i=0; i<4; i++)
+       {
+               token = _pico_parse( p,0 );
+               if (token == NULL)
+               {
+                       _pico_zero_vec4( out );
+                       return 0;
+               }
+               out[ i ] = (float) atof( token );
+       }
+       /* success */
+       return 1;
+}
+
+int _pico_parse_vec4_def( picoParser_t *p, picoVec4_t out, picoVec4_t def )
+{
+       char *token;
+       int       i;
+
+       /* sanity checks */
+       if (p == NULL || out == NULL)
+               return 0;
+
+       /* assign default vector value */
+       _pico_copy_vec4( def,out );
+
+       /* parse four vector components */
+       for (i=0; i<4; i++)
+       {
+               token = _pico_parse( p,0 );
+               if (token == NULL)
+               {
+                       _pico_copy_vec4( def,out );
+                       return 0;
+               }
+               out[ i ] = (float) atof( token );
+       }
+       /* success */
+       return 1;
+}
+
+/* _pico_new_memstream:
+ *  allocates a new memorystream object.
+ */
+picoMemStream_t *_pico_new_memstream( picoByte_t *buffer, int bufSize )
+{
+       picoMemStream_t *s;
+       
+       /* sanity check */
+       if( buffer == NULL || bufSize <= 0 )
+               return NULL;
+       
+       /* allocate stream */
+       s = _pico_alloc( sizeof(picoMemStream_t) );
+       if (s == NULL) return NULL;
+       memset( s,0,sizeof(picoMemStream_t) );
+
+       /* setup */
+       s->buffer       = buffer;
+       s->curPos       = buffer;
+       s->bufSize      = bufSize;
+       s->flag         = 0;
+
+       /* return ptr to stream */
+       return s;
+}
+
+/* _pico_free_memstream:
+ *  frees an existing pico memorystream object.
+ */
+void _pico_free_memstream( picoMemStream_t *s )
+{
+       /* sanity check */
+       if (s == NULL) return;
+
+       /* free the stream */
+       _pico_free( s );
+}
+
+/* _pico_memstream_read:
+ *  reads data from a pico memorystream into a buffer.
+ */
+int _pico_memstream_read( picoMemStream_t *s, void *buffer, int len )
+{
+       int ret = 1;
+
+       /* sanity checks */
+       if (s == NULL || buffer == NULL)
+               return 0;
+
+       if (s->curPos + len > s->buffer + s->bufSize)
+       {
+               s->flag |= PICO_IOEOF;
+               len = s->buffer + s->bufSize - s->curPos;
+               ret = 0;
+       }
+
+       /* read the data */
+       memcpy( buffer, s->curPos, len );
+       s->curPos += len;
+       return ret;
+}
+
+/* _pico_memstream_read:
+ *  reads a character from a pico memorystream
+ */
+int _pico_memstream_getc( picoMemStream_t *s )
+{
+       int c = 0;
+
+       /* sanity check */
+       if (s == NULL)
+               return -1;
+
+       /* read the character */
+       if (_pico_memstream_read( s, &c, 1) == 0)
+               return -1;
+
+       return c;
+}
+
+/* _pico_memstream_seek:
+ *  sets the current read position to a different location
+ */
+int _pico_memstream_seek( picoMemStream_t *s, long offset, int origin )
+{
+       int overflow;
+
+       /* sanity check */
+       if (s == NULL)
+               return -1;
+
+       if (origin == PICO_SEEK_SET)
+       {
+               s->curPos = s->buffer + offset;
+               overflow = s->curPos - ( s->buffer + s->bufSize );
+               if (overflow > 0)
+               {
+                       s->curPos = s->buffer + s->bufSize;
+                       return offset - overflow;
+               }
+               return 0;
+       }
+       else if (origin == PICO_SEEK_CUR)
+       {
+               s->curPos += offset;
+               overflow = s->curPos - ( s->buffer + s->bufSize );
+               if (overflow > 0)
+               {
+                       s->curPos = s->buffer + s->bufSize;
+                       return offset - overflow;
+               }
+               return 0;
+       }
+       else if (origin == PICO_SEEK_END)
+       {
+               s->curPos = ( s->buffer + s->bufSize ) - offset;
+               overflow = s->buffer - s->curPos;
+               if (overflow > 0)
+               {
+                       s->curPos = s->buffer;
+                       return offset - overflow;
+               }
+               return 0;
+       }
+
+       return -1;
+}
+
+/* _pico_memstream_tell:
+ *  returns the current read position in the pico memorystream
+ */
+long _pico_memstream_tell( picoMemStream_t *s )
+{
+       /* sanity check */
+       if (s == NULL)
+               return -1;
+
+       return s->curPos - s->buffer;
+}