/* =========================================================================== Return to Castle Wolfenstein multiplayer GPL Source Code Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”). RTCW MP Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. RTCW MP Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with RTCW MP Source Code. If not, see . In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ /***************************************************************************** * name: l_struct.c * * desc: structure reading / writing * * *****************************************************************************/ #ifdef BOTLIB #include "../game/q_shared.h" #include "../game/botlib.h" //for the include of be_interface.h #include "l_script.h" #include "l_precomp.h" #include "l_struct.h" #include "l_utils.h" #include "be_interface.h" #endif //BOTLIB #ifdef BSPC //include files for usage in the BSP Converter #include "../bspc/qbsp.h" #include "../bspc/l_log.h" #include "../bspc/l_mem.h" #include "l_precomp.h" #include "l_struct.h" #define qtrue true #define qfalse false #endif //BSPC //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== fielddef_t *FindField( fielddef_t *defs, char *name ) { int i; for ( i = 0; defs[i].name; i++ ) { if ( !strcmp( defs[i].name, name ) ) { return &defs[i]; } } //end for return NULL; } //end of the function FindField //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== qboolean ReadNumber( source_t *source, fielddef_t *fd, void *p ) { token_t token; int negative = qfalse; long int intval, intmin = 0, intmax = 0; double floatval; if ( !PC_ExpectAnyToken( source, &token ) ) { return 0; } //check for minus sign if ( token.type == TT_PUNCTUATION ) { if ( fd->type & FT_UNSIGNED ) { SourceError( source, "expected unsigned value, found %s", token.string ); return 0; } //end if //if not a minus sign if ( strcmp( token.string, "-" ) ) { SourceError( source, "unexpected punctuation %s", token.string ); return 0; } //end if negative = qtrue; //read the number if ( !PC_ExpectAnyToken( source, &token ) ) { return 0; } } //end if //check if it is a number if ( token.type != TT_NUMBER ) { SourceError( source, "expected number, found %s", token.string ); return 0; } //end if //check for a float value if ( token.subtype & TT_FLOAT ) { if ( ( fd->type & FT_TYPE ) != FT_FLOAT ) { SourceError( source, "unexpected float" ); return 0; } //end if floatval = token.floatvalue; if ( negative ) { floatval = -floatval; } if ( fd->type & FT_BOUNDED ) { if ( floatval < fd->floatmin || floatval > fd->floatmax ) { SourceError( source, "float out of range [%f, %f]", fd->floatmin, fd->floatmax ); return 0; } //end if } //end if *(float *) p = (float) floatval; return 1; } //end if // intval = token.intvalue; if ( negative ) { intval = -intval; } //check bounds if ( ( fd->type & FT_TYPE ) == FT_CHAR ) { if ( fd->type & FT_UNSIGNED ) { intmin = 0; intmax = 255; } else {intmin = -128; intmax = 127;} } //end if if ( ( fd->type & FT_TYPE ) == FT_INT ) { if ( fd->type & FT_UNSIGNED ) { intmin = 0; intmax = 65535; } else {intmin = -32768; intmax = 32767;} } //end else if if ( ( fd->type & FT_TYPE ) == FT_CHAR || ( fd->type & FT_TYPE ) == FT_INT ) { if ( fd->type & FT_BOUNDED ) { intmin = Maximum( intmin, fd->floatmin ); intmax = Minimum( intmax, fd->floatmax ); } //end if if ( intval < intmin || intval > intmax ) { SourceError( source, "value %d out of range [%d, %d]", intval, intmin, intmax ); return 0; } //end if } //end if else if ( ( fd->type & FT_TYPE ) == FT_FLOAT ) { if ( fd->type & FT_BOUNDED ) { if ( intval < fd->floatmin || intval > fd->floatmax ) { SourceError( source, "value %d out of range [%f, %f]", intval, fd->floatmin, fd->floatmax ); return 0; } //end if } //end if } //end else if //store the value if ( ( fd->type & FT_TYPE ) == FT_CHAR ) { if ( fd->type & FT_UNSIGNED ) { *(unsigned char *) p = (unsigned char) intval; } else { *(char *) p = (char) intval;} } //end if else if ( ( fd->type & FT_TYPE ) == FT_INT ) { if ( fd->type & FT_UNSIGNED ) { *(unsigned int *) p = (unsigned int) intval; } else { *(int *) p = (int) intval;} } //end else else if ( ( fd->type & FT_TYPE ) == FT_FLOAT ) { *(float *) p = (float) intval; } //end else return 1; } //end of the function ReadNumber //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== qboolean ReadChar( source_t *source, fielddef_t *fd, void *p ) { token_t token; if ( !PC_ExpectAnyToken( source, &token ) ) { return 0; } //take literals into account if ( token.type == TT_LITERAL ) { StripSingleQuotes( token.string ); *(char *) p = token.string[0]; } //end if else { PC_UnreadLastToken( source ); if ( !ReadNumber( source, fd, p ) ) { return 0; } } //end if return 1; } //end of the function ReadChar //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int ReadString( source_t *source, fielddef_t *fd, void *p ) { token_t token; if ( !PC_ExpectTokenType( source, TT_STRING, 0, &token ) ) { return 0; } //remove the double quotes StripDoubleQuotes( token.string ); //copy the string strncpy( (char *) p, token.string, MAX_STRINGFIELD ); //make sure the string is closed with a zero ( (char *)p )[MAX_STRINGFIELD - 1] = '\0'; // return 1; } //end of the function ReadString //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int ReadStructure( source_t *source, structdef_t *def, char *structure ) { token_t token; fielddef_t *fd; void *p; int num; if ( !PC_ExpectTokenString( source, "{" ) ) { return 0; } while ( 1 ) { if ( !PC_ExpectAnyToken( source, &token ) ) { return qfalse; } //if end of structure if ( !strcmp( token.string, "}" ) ) { break; } //find the field with the name fd = FindField( def->fields, token.string ); if ( !fd ) { SourceError( source, "unknown structure field %s", token.string ); return qfalse; } //end if if ( fd->type & FT_ARRAY ) { num = fd->maxarray; if ( !PC_ExpectTokenString( source, "{" ) ) { return qfalse; } } //end if else { num = 1; } //end else p = ( void * )( structure + fd->offset ); while ( num-- > 0 ) { if ( fd->type & FT_ARRAY ) { if ( PC_CheckTokenString( source, "}" ) ) { break; } } //end if switch ( fd->type & FT_TYPE ) { case FT_CHAR: { if ( !ReadChar( source, fd, p ) ) { return qfalse; } p = (char *) p + sizeof( char ); break; } //end case case FT_INT: { if ( !ReadNumber( source, fd, p ) ) { return qfalse; } p = (char *) p + sizeof( int ); break; } //end case case FT_FLOAT: { if ( !ReadNumber( source, fd, p ) ) { return qfalse; } p = (char *) p + sizeof( float ); break; } //end case case FT_STRING: { if ( !ReadString( source, fd, p ) ) { return qfalse; } p = (char *) p + MAX_STRINGFIELD; break; } //end case case FT_STRUCT: { if ( !fd->substruct ) { SourceError( source, "BUG: no sub structure defined" ); return qfalse; } //end if ReadStructure( source, fd->substruct, (char *) p ); p = (char *) p + fd->substruct->size; break; } //end case } //end switch if ( fd->type & FT_ARRAY ) { if ( !PC_ExpectAnyToken( source, &token ) ) { return qfalse; } if ( !strcmp( token.string, "}" ) ) { break; } if ( strcmp( token.string, "," ) ) { SourceError( source, "expected a comma, found %s", token.string ); return qfalse; } //end if } //end if } //end while } //end while return qtrue; } //end of the function ReadStructure //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int WriteIndent( FILE *fp, int indent ) { while ( indent-- > 0 ) { if ( fprintf( fp, "\t" ) < 0 ) { return qfalse; } } //end while return qtrue; } //end of the function WriteIndent //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int WriteFloat( FILE *fp, float value ) { char buf[128]; int l; sprintf( buf, "%f", value ); l = strlen( buf ); //strip any trailing zeros while ( l-- > 1 ) { if ( buf[l] != '0' && buf[l] != '.' ) { break; } if ( buf[l] == '.' ) { buf[l] = 0; break; } //end if buf[l] = 0; } //end while //write the float to file if ( fprintf( fp, "%s", buf ) < 0 ) { return 0; } return 1; } //end of the function WriteFloat //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int WriteStructWithIndent( FILE *fp, structdef_t *def, char *structure, int indent ) { int i, num; void *p; fielddef_t *fd; if ( !WriteIndent( fp, indent ) ) { return qfalse; } if ( fprintf( fp, "{\r\n" ) < 0 ) { return qfalse; } indent++; for ( i = 0; def->fields[i].name; i++ ) { fd = &def->fields[i]; if ( !WriteIndent( fp, indent ) ) { return qfalse; } if ( fprintf( fp, "%s\t", fd->name ) < 0 ) { return qfalse; } p = ( void * )( structure + fd->offset ); if ( fd->type & FT_ARRAY ) { num = fd->maxarray; if ( fprintf( fp, "{" ) < 0 ) { return qfalse; } } //end if else { num = 1; } //end else while ( num-- > 0 ) { switch ( fd->type & FT_TYPE ) { case FT_CHAR: { if ( fprintf( fp, "%d", *(char *) p ) < 0 ) { return qfalse; } p = (char *) p + sizeof( char ); break; } //end case case FT_INT: { if ( fprintf( fp, "%d", *(int *) p ) < 0 ) { return qfalse; } p = (char *) p + sizeof( int ); break; } //end case case FT_FLOAT: { if ( !WriteFloat( fp, *(float *)p ) ) { return qfalse; } p = (char *) p + sizeof( float ); break; } //end case case FT_STRING: { if ( fprintf( fp, "\"%s\"", (char *) p ) < 0 ) { return qfalse; } p = (char *) p + MAX_STRINGFIELD; break; } //end case case FT_STRUCT: { if ( !WriteStructWithIndent( fp, fd->substruct, structure, indent ) ) { return qfalse; } p = (char *) p + fd->substruct->size; break; } //end case } //end switch if ( fd->type & FT_ARRAY ) { if ( num > 0 ) { if ( fprintf( fp, "," ) < 0 ) { return qfalse; } } //end if else { if ( fprintf( fp, "}" ) < 0 ) { return qfalse; } } //end else } //end if } //end while if ( fprintf( fp, "\r\n" ) < 0 ) { return qfalse; } } //end for indent--; if ( !WriteIndent( fp, indent ) ) { return qfalse; } if ( fprintf( fp, "}\r\n" ) < 0 ) { return qfalse; } return qtrue; } //end of the function WriteStructWithIndent //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int WriteStructure( FILE *fp, structdef_t *def, char *structure ) { return WriteStructWithIndent( fp, def, structure, 0 ); } //end of the function WriteStructure