diff options
| author | Simon Robertshaw <simon@hardwired.org.uk> | 2011-12-30 02:06:31 (GMT) |
|---|---|---|
| committer | Simon Robertshaw <simon@hardwired.org.uk> | 2011-12-30 02:06:31 (GMT) |
| commit | 86369670aaa11b8cd2ddcbd46413fb9482e4e58f (patch) | |
| tree | 07be282e1e08003153ee5c000f3e50336cfa2eb0 /src | |
| parent | ad2b000a8af84f299e7c7c43a6a272a60ffcd36d (diff) | |
| download | powder-86369670aaa11b8cd2ddcbd46413fb9482e4e58f.zip powder-86369670aaa11b8cd2ddcbd46413fb9482e4e58f.tar.gz | |
Add checks for prerender_save in save_filename_ui, pass vx, vy and pv air data into parse and build save methods. New save format: OPS, basic reading and writing complete, uses BSON, BSON.c/h (Binary JSON) implementation from MongoDB. (Is License OK?)
Diffstat (limited to 'src')
| -rw-r--r-- | src/BSON.c | 1122 | ||||
| -rw-r--r-- | src/interface.c | 19 | ||||
| -rw-r--r-- | src/main.c | 867 | ||||
| -rw-r--r-- | src/save.c | 1266 |
4 files changed, 2409 insertions, 865 deletions
diff --git a/src/BSON.c b/src/BSON.c new file mode 100644 index 0000000..62dfc4f --- /dev/null +++ b/src/BSON.c @@ -0,0 +1,1122 @@ +/* bson.c */ + +/* Copyright 2009, 2010 10gen Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <time.h> +#include <limits.h> + +#include "bson.h" + +const int initialBufferSize = 128; + +/* only need one of these */ +static const int zero = 0; + +/* Custom standard function pointers. */ +void *( *bson_malloc_func )( size_t ) = malloc; +void *( *bson_realloc_func )( void *, size_t ) = realloc; +void ( *bson_free )( void * ) = free; +bson_printf_func bson_printf = printf; +bson_fprintf_func bson_fprintf = fprintf; +bson_sprintf_func bson_sprintf = sprintf; + +static int _bson_errprintf( const char *, ... ); +bson_printf_func bson_errprintf = _bson_errprintf; + +/* ObjectId fuzz functions. */ +static int ( *oid_fuzz_func )( void ) = NULL; +static int ( *oid_inc_func )( void ) = NULL; + +/* ---------------------------- + READING + ------------------------------ */ + +bson *bson_empty( bson *obj ) { + static char *data = "\005\0\0\0\0"; + bson_init_data( obj, data ); + obj->finished = 1; + obj->err = 0; + obj->stackPos = 0; + return obj; +} + +int bson_copy( bson *out, const bson *in ) { + if ( !out ) return BSON_ERROR; + if ( !in->finished ) return BSON_ERROR; + bson_init_size( out, bson_size( in ) ); + memcpy( out->data, in->data, bson_size( in ) ); + out->finished = 1; + + return BSON_OK; +} + +int bson_init_data( bson *b, char *data ) { + b->data = data; + return BSON_OK; +} + +int bson_init_finished_data( bson *b, char *data ) { + bson_init_data( b, data ); + b->stackPos = 0; + b->finished = 1; + return BSON_OK; +} + +static void _bson_reset( bson *b ) { + b->finished = 0; + b->stackPos = 0; + b->err = 0; + b->errstr = NULL; +} + +int bson_size( const bson *b ) { + int i; + if ( ! b || ! b->data ) + return 0; + bson_little_endian32( &i, b->data ); + return i; +} + +const char *bson_data( bson *b ) { + return (const char *)b->data; +} + +static char hexbyte( char hex ) { + switch ( hex ) { + case '0': + return 0x0; + case '1': + return 0x1; + case '2': + return 0x2; + case '3': + return 0x3; + case '4': + return 0x4; + case '5': + return 0x5; + case '6': + return 0x6; + case '7': + return 0x7; + case '8': + return 0x8; + case '9': + return 0x9; + case 'a': + case 'A': + return 0xa; + case 'b': + case 'B': + return 0xb; + case 'c': + case 'C': + return 0xc; + case 'd': + case 'D': + return 0xd; + case 'e': + case 'E': + return 0xe; + case 'f': + case 'F': + return 0xf; + default: + return 0x0; /* something smarter? */ + } +} + +void bson_oid_from_string( bson_oid_t *oid, const char *str ) { + int i; + for ( i=0; i<12; i++ ) { + oid->bytes[i] = ( hexbyte( str[2*i] ) << 4 ) | hexbyte( str[2*i + 1] ); + } +} + +void bson_oid_to_string( const bson_oid_t *oid, char *str ) { + static const char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + int i; + for ( i=0; i<12; i++ ) { + str[2*i] = hex[( oid->bytes[i] & 0xf0 ) >> 4]; + str[2*i + 1] = hex[ oid->bytes[i] & 0x0f ]; + } + str[24] = '\0'; +} + +void bson_set_oid_fuzz( int ( *func )( void ) ) { + oid_fuzz_func = func; +} + +void bson_set_oid_inc( int ( *func )( void ) ) { + oid_inc_func = func; +} + +void bson_oid_gen( bson_oid_t *oid ) { + static int incr = 0; + static int fuzz = 0; + int i; + int t = time( NULL ); + + if( oid_inc_func ) + i = oid_inc_func(); + else + i = incr++; + + if ( !fuzz ) { + if ( oid_fuzz_func ) + fuzz = oid_fuzz_func(); + else { + srand( t ); + fuzz = rand(); + } + } + + bson_big_endian32( &oid->ints[0], &t ); + oid->ints[1] = fuzz; + bson_big_endian32( &oid->ints[2], &i ); +} + +time_t bson_oid_generated_time( bson_oid_t *oid ) { + time_t out; + bson_big_endian32( &out, &oid->ints[0] ); + + return out; +} + +void bson_print( bson *b ) { + bson_print_raw( b->data , 0 ); +} + +void bson_print_raw( const char *data , int depth ) { + bson_iterator i; + const char *key; + int temp; + bson_timestamp_t ts; + char oidhex[25]; + bson scope; + bson_iterator_from_buffer( &i, data ); + + while ( bson_iterator_next( &i ) ) { + bson_type t = bson_iterator_type( &i ); + if ( t == 0 ) + break; + key = bson_iterator_key( &i ); + + for ( temp=0; temp<=depth; temp++ ) + bson_printf( "\t" ); + bson_printf( "%s : %d \t " , key , t ); + switch ( t ) { + case BSON_DOUBLE: + bson_printf( "%f" , bson_iterator_double( &i ) ); + break; + case BSON_STRING: + bson_printf( "%s" , bson_iterator_string( &i ) ); + break; + case BSON_SYMBOL: + bson_printf( "SYMBOL: %s" , bson_iterator_string( &i ) ); + break; + case BSON_OID: + bson_oid_to_string( bson_iterator_oid( &i ), oidhex ); + bson_printf( "%s" , oidhex ); + break; + case BSON_BOOL: + bson_printf( "%s" , bson_iterator_bool( &i ) ? "true" : "false" ); + break; + case BSON_DATE: + bson_printf( "%ld" , ( long int )bson_iterator_date( &i ) ); + break; + case BSON_BINDATA: + bson_printf( "BSON_BINDATA" ); + break; + case BSON_UNDEFINED: + bson_printf( "BSON_UNDEFINED" ); + break; + case BSON_NULL: + bson_printf( "BSON_NULL" ); + break; + case BSON_REGEX: + bson_printf( "BSON_REGEX: %s", bson_iterator_regex( &i ) ); + break; + case BSON_CODE: + bson_printf( "BSON_CODE: %s", bson_iterator_code( &i ) ); + break; + case BSON_CODEWSCOPE: + bson_printf( "BSON_CODE_W_SCOPE: %s", bson_iterator_code( &i ) ); + bson_init( &scope ); + bson_iterator_code_scope( &i, &scope ); + bson_printf( "\n\t SCOPE: " ); + bson_print( &scope ); + break; + case BSON_INT: + bson_printf( "%d" , bson_iterator_int( &i ) ); + break; + case BSON_LONG: + bson_printf( "%lld" , ( uint64_t )bson_iterator_long( &i ) ); + break; + case BSON_TIMESTAMP: + ts = bson_iterator_timestamp( &i ); + bson_printf( "i: %d, t: %d", ts.i, ts.t ); + break; + case BSON_OBJECT: + case BSON_ARRAY: + bson_printf( "\n" ); + bson_print_raw( bson_iterator_value( &i ) , depth + 1 ); + break; + default: + bson_errprintf( "can't print type : %d\n" , t ); + } + bson_printf( "\n" ); + } +} + +/* ---------------------------- + ITERATOR + ------------------------------ */ + +void bson_iterator_init( bson_iterator *i, const bson *b ) { + i->cur = b->data + 4; + i->first = 1; +} + +void bson_iterator_from_buffer( bson_iterator *i, const char *buffer ) { + i->cur = buffer + 4; + i->first = 1; +} + +bson_type bson_find( bson_iterator *it, const bson *obj, const char *name ) { + bson_iterator_init( it, (bson *)obj ); + while( bson_iterator_next( it ) ) { + if ( strcmp( name, bson_iterator_key( it ) ) == 0 ) + break; + } + return bson_iterator_type( it ); +} + +bson_bool_t bson_iterator_more( const bson_iterator *i ) { + return *( i->cur ); +} + +bson_type bson_iterator_next( bson_iterator *i ) { + int ds; + + if ( i->first ) { + i->first = 0; + return ( bson_type )( *i->cur ); + } + + switch ( bson_iterator_type( i ) ) { + case BSON_EOO: + return BSON_EOO; /* don't advance */ + case BSON_UNDEFINED: + case BSON_NULL: + ds = 0; + break; + case BSON_BOOL: + ds = 1; + break; + case BSON_INT: + ds = 4; + break; + case BSON_LONG: + case BSON_DOUBLE: + case BSON_TIMESTAMP: + case BSON_DATE: + ds = 8; + break; + case BSON_OID: + ds = 12; + break; + case BSON_STRING: + case BSON_SYMBOL: + case BSON_CODE: + ds = 4 + bson_iterator_int_raw( i ); + break; + case BSON_BINDATA: + ds = 5 + bson_iterator_int_raw( i ); + break; + case BSON_OBJECT: + case BSON_ARRAY: + case BSON_CODEWSCOPE: + ds = bson_iterator_int_raw( i ); + break; + case BSON_DBREF: + ds = 4+12 + bson_iterator_int_raw( i ); + break; + case BSON_REGEX: { + const char *s = bson_iterator_value( i ); + const char *p = s; + p += strlen( p )+1; + p += strlen( p )+1; + ds = p-s; + break; + } + + default: { + char msg[] = "unknown type: 000000000000"; + bson_numstr( msg+14, ( unsigned )( i->cur[0] ) ); + bson_fatal_msg( 0, msg ); + return 0; + } + } + + i->cur += 1 + strlen( i->cur + 1 ) + 1 + ds; + + return ( bson_type )( *i->cur ); +} + +bson_type bson_iterator_type( const bson_iterator *i ) { + return ( bson_type )i->cur[0]; +} + +const char *bson_iterator_key( const bson_iterator *i ) { + return i->cur + 1; +} + +const char *bson_iterator_value( const bson_iterator *i ) { + const char *t = i->cur + 1; + t += strlen( t ) + 1; + return t; +} + +/* types */ + +int bson_iterator_int_raw( const bson_iterator *i ) { + int out; + bson_little_endian32( &out, bson_iterator_value( i ) ); + return out; +} + +double bson_iterator_double_raw( const bson_iterator *i ) { + double out; + bson_little_endian64( &out, bson_iterator_value( i ) ); + return out; +} + +int64_t bson_iterator_long_raw( const bson_iterator *i ) { + int64_t out; + bson_little_endian64( &out, bson_iterator_value( i ) ); + return out; +} + +bson_bool_t bson_iterator_bool_raw( const bson_iterator *i ) { + return bson_iterator_value( i )[0]; +} + +bson_oid_t *bson_iterator_oid( const bson_iterator *i ) { + return ( bson_oid_t * )bson_iterator_value( i ); +} + +int bson_iterator_int( const bson_iterator *i ) { + switch ( bson_iterator_type( i ) ) { + case BSON_INT: + return bson_iterator_int_raw( i ); + case BSON_LONG: + return bson_iterator_long_raw( i ); + case BSON_DOUBLE: + return bson_iterator_double_raw( i ); + default: + return 0; + } +} + +double bson_iterator_double( const bson_iterator *i ) { + switch ( bson_iterator_type( i ) ) { + case BSON_INT: + return bson_iterator_int_raw( i ); + case BSON_LONG: + return bson_iterator_long_raw( i ); + case BSON_DOUBLE: + return bson_iterator_double_raw( i ); + default: + return 0; + } +} + +int64_t bson_iterator_long( const bson_iterator *i ) { + switch ( bson_iterator_type( i ) ) { + case BSON_INT: + return bson_iterator_int_raw( i ); + case BSON_LONG: + return bson_iterator_long_raw( i ); + case BSON_DOUBLE: + return bson_iterator_double_raw( i ); + default: + return 0; + } +} + +bson_timestamp_t bson_iterator_timestamp( const bson_iterator *i ) { + bson_timestamp_t ts; + bson_little_endian32( &( ts.i ), bson_iterator_value( i ) ); + bson_little_endian32( &( ts.t ), bson_iterator_value( i ) + 4 ); + return ts; +} + +bson_bool_t bson_iterator_bool( const bson_iterator *i ) { + switch ( bson_iterator_type( i ) ) { + case BSON_BOOL: + return bson_iterator_bool_raw( i ); + case BSON_INT: + return bson_iterator_int_raw( i ) != 0; + case BSON_LONG: + return bson_iterator_long_raw( i ) != 0; + case BSON_DOUBLE: + return bson_iterator_double_raw( i ) != 0; + case BSON_EOO: + case BSON_NULL: + return 0; + default: + return 1; + } +} + +const char *bson_iterator_string( const bson_iterator *i ) { + return bson_iterator_value( i ) + 4; +} + +int bson_iterator_string_len( const bson_iterator *i ) { + return bson_iterator_int_raw( i ); +} + +const char *bson_iterator_code( const bson_iterator *i ) { + switch ( bson_iterator_type( i ) ) { + case BSON_STRING: + case BSON_CODE: + return bson_iterator_value( i ) + 4; + case BSON_CODEWSCOPE: + return bson_iterator_value( i ) + 8; + default: + return NULL; + } +} + +void bson_iterator_code_scope( const bson_iterator *i, bson *scope ) { + if ( bson_iterator_type( i ) == BSON_CODEWSCOPE ) { + int code_len; + bson_little_endian32( &code_len, bson_iterator_value( i )+4 ); + bson_init_data( scope, ( void * )( bson_iterator_value( i )+8+code_len ) ); + _bson_reset( scope ); + scope->finished = 1; + } else { + bson_empty( scope ); + } +} + +bson_date_t bson_iterator_date( const bson_iterator *i ) { + return bson_iterator_long_raw( i ); +} + +time_t bson_iterator_time_t( const bson_iterator *i ) { + return bson_iterator_date( i ) / 1000; +} + +int bson_iterator_bin_len( const bson_iterator *i ) { + return ( bson_iterator_bin_type( i ) == BSON_BIN_BINARY_OLD ) + ? bson_iterator_int_raw( i ) - 4 + : bson_iterator_int_raw( i ); +} + +char bson_iterator_bin_type( const bson_iterator *i ) { + return bson_iterator_value( i )[4]; +} + +const char *bson_iterator_bin_data( const bson_iterator *i ) { + return ( bson_iterator_bin_type( i ) == BSON_BIN_BINARY_OLD ) + ? bson_iterator_value( i ) + 9 + : bson_iterator_value( i ) + 5; +} + +const char *bson_iterator_regex( const bson_iterator *i ) { + return bson_iterator_value( i ); +} + +const char *bson_iterator_regex_opts( const bson_iterator *i ) { + const char *p = bson_iterator_value( i ); + return p + strlen( p ) + 1; + +} + +void bson_iterator_subobject( const bson_iterator *i, bson *sub ) { + bson_init_data( sub, ( char * )bson_iterator_value( i ) ); + _bson_reset( sub ); + sub->finished = 1; +} + +void bson_iterator_subiterator( const bson_iterator *i, bson_iterator *sub ) { + bson_iterator_from_buffer( sub, bson_iterator_value( i ) ); +} + +/* ---------------------------- + BUILDING + ------------------------------ */ + +static void _bson_init_size( bson *b, int size ) { + if( size == 0 ) + b->data = NULL; + else + b->data = ( char * )bson_malloc( size ); + b->dataSize = size; + b->cur = b->data + 4; + _bson_reset( b ); +} + +void bson_init( bson *b ) { + _bson_init_size( b, initialBufferSize ); +} + +void bson_init_size( bson *b, int size ) { + _bson_init_size( b, size ); +} + +static void bson_append_byte( bson *b, char c ) { + b->cur[0] = c; + b->cur++; +} + +static void bson_append( bson *b, const void *data, int len ) { + memcpy( b->cur , data , len ); + b->cur += len; +} + +static void bson_append32( bson *b, const void *data ) { + bson_little_endian32( b->cur, data ); + b->cur += 4; +} + +static void bson_append64( bson *b, const void *data ) { + bson_little_endian64( b->cur, data ); + b->cur += 8; +} + +int bson_ensure_space( bson *b, const int bytesNeeded ) { + int pos = b->cur - b->data; + char *orig = b->data; + int new_size; + + if ( pos + bytesNeeded <= b->dataSize ) + return BSON_OK; + + new_size = 1.5 * ( b->dataSize + bytesNeeded ); + + if( new_size < b->dataSize ) { + if( ( b->dataSize + bytesNeeded ) < INT_MAX ) + new_size = INT_MAX; + else { + b->err = BSON_SIZE_OVERFLOW; + return BSON_ERROR; + } + } + + b->data = bson_realloc( b->data, new_size ); + if ( !b->data ) + bson_fatal_msg( !!b->data, "realloc() failed" ); + + b->dataSize = new_size; + b->cur += b->data - orig; + + return BSON_OK; +} + +int bson_finish( bson *b ) { + int i; + + if( b->err & BSON_NOT_UTF8 ) + return BSON_ERROR; + + if ( ! b->finished ) { + if ( bson_ensure_space( b, 1 ) == BSON_ERROR ) return BSON_ERROR; + bson_append_byte( b, 0 ); + i = b->cur - b->data; + bson_little_endian32( b->data, &i ); + b->finished = 1; + } + + return BSON_OK; +} + +void bson_destroy( bson *b ) { + bson_free( b->data ); + b->err = 0; + b->data = 0; + b->cur = 0; + b->finished = 1; +} + +static int bson_append_estart( bson *b, int type, const char *name, const int dataSize ) { + const int len = strlen( name ) + 1; + + if ( b->finished ) { + b->err |= BSON_ALREADY_FINISHED; + return BSON_ERROR; + } + + if ( bson_ensure_space( b, 1 + len + dataSize ) == BSON_ERROR ) { + return BSON_ERROR; + } + + if( bson_check_field_name( b, ( const char * )name, len - 1 ) == BSON_ERROR ) { + bson_builder_error( b ); + return BSON_ERROR; + } + + bson_append_byte( b, ( char )type ); + bson_append( b, name, len ); + return BSON_OK; +} + +/* ---------------------------- + BUILDING TYPES + ------------------------------ */ + +int bson_append_int( bson *b, const char *name, const int i ) { + if ( bson_append_estart( b, BSON_INT, name, 4 ) == BSON_ERROR ) + return BSON_ERROR; + bson_append32( b , &i ); + return BSON_OK; +} + +int bson_append_long( bson *b, const char *name, const int64_t i ) { + if ( bson_append_estart( b , BSON_LONG, name, 8 ) == BSON_ERROR ) + return BSON_ERROR; + bson_append64( b , &i ); + return BSON_OK; +} + +int bson_append_double( bson *b, const char *name, const double d ) { + if ( bson_append_estart( b, BSON_DOUBLE, name, 8 ) == BSON_ERROR ) + return BSON_ERROR; + bson_append64( b , &d ); + return BSON_OK; +} + +int bson_append_bool( bson *b, const char *name, const bson_bool_t i ) { + if ( bson_append_estart( b, BSON_BOOL, name, 1 ) == BSON_ERROR ) + return BSON_ERROR; + bson_append_byte( b , i != 0 ); + return BSON_OK; +} + +int bson_append_null( bson *b, const char *name ) { + if ( bson_append_estart( b , BSON_NULL, name, 0 ) == BSON_ERROR ) + return BSON_ERROR; + return BSON_OK; +} + +int bson_append_undefined( bson *b, const char *name ) { + if ( bson_append_estart( b, BSON_UNDEFINED, name, 0 ) == BSON_ERROR ) + return BSON_ERROR; + return BSON_OK; +} + +static int bson_append_string_base( bson *b, const char *name, + const char *value, int len, bson_type type ) { + + int sl = len + 1; + if ( bson_check_string( b, ( const char * )value, sl - 1 ) == BSON_ERROR ) + return BSON_ERROR; + if ( bson_append_estart( b, type, name, 4 + sl ) == BSON_ERROR ) { + return BSON_ERROR; + } + bson_append32( b , &sl ); + bson_append( b , value , sl - 1 ); + bson_append( b , "\0" , 1 ); + return BSON_OK; +} + +int bson_append_string( bson *b, const char *name, const char *value ) { + return bson_append_string_base( b, name, value, strlen ( value ), BSON_STRING ); +} + +int bson_append_symbol( bson *b, const char *name, const char *value ) { + return bson_append_string_base( b, name, value, strlen ( value ), BSON_SYMBOL ); +} + +int bson_append_code( bson *b, const char *name, const char *value ) { + return bson_append_string_base( b, name, value, strlen ( value ), BSON_CODE ); +} + +int bson_append_string_n( bson *b, const char *name, const char *value, int len ) { + return bson_append_string_base( b, name, value, len, BSON_STRING ); +} + +int bson_append_symbol_n( bson *b, const char *name, const char *value, int len ) { + return bson_append_string_base( b, name, value, len, BSON_SYMBOL ); +} + +int bson_append_code_n( bson *b, const char *name, const char *value, int len ) { + return bson_append_string_base( b, name, value, len, BSON_CODE ); +} + +int bson_append_code_w_scope_n( bson *b, const char *name, + const char *code, int len, const bson *scope ) { + + int sl = len + 1; + int size = 4 + 4 + sl + bson_size( scope ); + if ( bson_append_estart( b, BSON_CODEWSCOPE, name, size ) == BSON_ERROR ) + return BSON_ERROR; + bson_append32( b, &size ); + bson_append32( b, &sl ); + bson_append( b, code, sl ); + bson_append( b, scope->data, bson_size( scope ) ); + return BSON_OK; +} + +int bson_append_code_w_scope( bson *b, const char *name, const char *code, const bson *scope ) { + return bson_append_code_w_scope_n( b, name, code, strlen ( code ), scope ); +} + +int bson_append_binary( bson *b, const char *name, char type, const char *str, int len ) { + if ( type == BSON_BIN_BINARY_OLD ) { + int subtwolen = len + 4; + if ( bson_append_estart( b, BSON_BINDATA, name, 4+1+4+len ) == BSON_ERROR ) + return BSON_ERROR; + bson_append32( b, &subtwolen ); + bson_append_byte( b, type ); + bson_append32( b, &len ); + bson_append( b, str, len ); + } else { + if ( bson_append_estart( b, BSON_BINDATA, name, 4+1+len ) == BSON_ERROR ) + return BSON_ERROR; + bson_append32( b, &len ); + bson_append_byte( b, type ); + bson_append( b, str, len ); + } + return BSON_OK; +} + +int bson_append_oid( bson *b, const char *name, const bson_oid_t *oid ) { + if ( bson_append_estart( b, BSON_OID, name, 12 ) == BSON_ERROR ) + return BSON_ERROR; + bson_append( b , oid , 12 ); + return BSON_OK; +} + +int bson_append_new_oid( bson *b, const char *name ) { + bson_oid_t oid; + bson_oid_gen( &oid ); + return bson_append_oid( b, name, &oid ); +} + +int bson_append_regex( bson *b, const char *name, const char *pattern, const char *opts ) { + const int plen = strlen( pattern )+1; + const int olen = strlen( opts )+1; + if ( bson_append_estart( b, BSON_REGEX, name, plen + olen ) == BSON_ERROR ) + return BSON_ERROR; + if ( bson_check_string( b, pattern, plen - 1 ) == BSON_ERROR ) + return BSON_ERROR; + bson_append( b , pattern , plen ); + bson_append( b , opts , olen ); + return BSON_OK; +} + +int bson_append_bson( bson *b, const char *name, const bson *bson ) { + if ( bson_append_estart( b, BSON_OBJECT, name, bson_size( bson ) ) == BSON_ERROR ) + return BSON_ERROR; + bson_append( b , bson->data , bson_size( bson ) ); + return BSON_OK; +} + +int bson_append_element( bson *b, const char *name_or_null, const bson_iterator *elem ) { + bson_iterator next = *elem; + int size; + + bson_iterator_next( &next ); + size = next.cur - elem->cur; + + if ( name_or_null == NULL ) { + if( bson_ensure_space( b, size ) == BSON_ERROR ) + return BSON_ERROR; + bson_append( b, elem->cur, size ); + } else { + int data_size = size - 2 - strlen( bson_iterator_key( elem ) ); + bson_append_estart( b, elem->cur[0], name_or_null, data_size ); + bson_append( b, bson_iterator_value( elem ), data_size ); + } + + return BSON_OK; +} + +int bson_append_timestamp( bson *b, const char *name, bson_timestamp_t *ts ) { + if ( bson_append_estart( b, BSON_TIMESTAMP, name, 8 ) == BSON_ERROR ) return BSON_ERROR; + + bson_append32( b , &( ts->i ) ); + bson_append32( b , &( ts->t ) ); + + return BSON_OK; +} + +int bson_append_date( bson *b, const char *name, bson_date_t millis ) { + if ( bson_append_estart( b, BSON_DATE, name, 8 ) == BSON_ERROR ) return BSON_ERROR; + bson_append64( b , &millis ); + return BSON_OK; +} + +int bson_append_time_t( bson *b, const char *name, time_t secs ) { + return bson_append_date( b, name, ( bson_date_t )secs * 1000 ); +} + +int bson_append_start_object( bson *b, const char *name ) { + if ( bson_append_estart( b, BSON_OBJECT, name, 5 ) == BSON_ERROR ) return BSON_ERROR; + b->stack[ b->stackPos++ ] = b->cur - b->data; + bson_append32( b , &zero ); + return BSON_OK; +} + +int bson_append_start_array( bson *b, const char *name ) { + if ( bson_append_estart( b, BSON_ARRAY, name, 5 ) == BSON_ERROR ) return BSON_ERROR; + b->stack[ b->stackPos++ ] = b->cur - b->data; + bson_append32( b , &zero ); + return BSON_OK; +} + +int bson_append_finish_object( bson *b ) { + char *start; + int i; + if ( bson_ensure_space( b, 1 ) == BSON_ERROR ) return BSON_ERROR; + bson_append_byte( b , 0 ); + + start = b->data + b->stack[ --b->stackPos ]; + i = b->cur - start; + bson_little_endian32( start, &i ); + + return BSON_OK; +} + +int bson_append_finish_array( bson *b ) { + return bson_append_finish_object( b ); +} + + +/* Error handling and allocators. */ + +static bson_err_handler err_handler = NULL; + +bson_err_handler set_bson_err_handler( bson_err_handler func ) { + bson_err_handler old = err_handler; + err_handler = func; + return old; +} + +void *bson_malloc( int size ) { + void *p; + p = bson_malloc_func( size ); + bson_fatal_msg( !!p, "malloc() failed" ); + return p; +} + +void *bson_realloc( void *ptr, int size ) { + void *p; + p = bson_realloc_func( ptr, size ); + bson_fatal_msg( !!p, "realloc() failed" ); + return p; +} + +int _bson_errprintf( const char *format, ... ) { + va_list ap; + int ret; + va_start( ap, format ); + ret = vfprintf( stderr, format, ap ); + va_end( ap ); + + return ret; +} + +/** + * This method is invoked when a non-fatal bson error is encountered. + * Calls the error handler if available. + * + * @param + */ +void bson_builder_error( bson *b ) { + if( err_handler ) + err_handler( "BSON error." ); +} + +void bson_fatal( int ok ) { + bson_fatal_msg( ok, "" ); +} + +void bson_fatal_msg( int ok , const char *msg ) { + if ( ok ) + return; + + if ( err_handler ) { + err_handler( msg ); + } + + bson_errprintf( "error: %s\n" , msg ); + exit( -5 ); +} + + +/* Efficiently copy an integer to a string. */ + +void bson_numstr( char *str, int i ) { + if( i < 1000 ) + memcpy( str, bson_numstrs[i], 4 ); + else + bson_sprintf( str,"%d", i ); +} + +/* encoding.c */ + +/* + * Copyright 2009-2011 10gen, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Portions Copyright 2001 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + */ +static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +/* --------------------------------------------------------------------- */ + +/* + * Utility routine to tell whether a sequence of bytes is legal UTF-8. + * This must be called with the length pre-determined by the first byte. + * The length can be set by: + * length = trailingBytesForUTF8[*source]+1; + * and the sequence is illegal right away if there aren't that many bytes + * available. + * If presented with a length > 4, this returns 0. The Unicode + * definition of UTF-8 goes up to 4-byte sequences. + */ +static int isLegalUTF8( const unsigned char *source, int length ) { + unsigned char a; + const unsigned char *srcptr = source + length; + switch ( length ) { + default: + return 0; + /* Everything else falls through when "true"... */ + case 4: + if ( ( a = ( *--srcptr ) ) < 0x80 || a > 0xBF ) return 0; + case 3: + if ( ( a = ( *--srcptr ) ) < 0x80 || a > 0xBF ) return 0; + case 2: + if ( ( a = ( *--srcptr ) ) > 0xBF ) return 0; + switch ( *source ) { + /* no fall-through in this inner switch */ + case 0xE0: + if ( a < 0xA0 ) return 0; + break; + case 0xF0: + if ( a < 0x90 ) return 0; + break; + case 0xF4: + if ( a > 0x8F ) return 0; + break; + default: + if ( a < 0x80 ) return 0; + } + case 1: + if ( *source >= 0x80 && *source < 0xC2 ) return 0; + if ( *source > 0xF4 ) return 0; + } + return 1; +} + +static int bson_validate_string( bson *b, const unsigned char *string, + const int length, const char check_utf8, const char check_dot, + const char check_dollar ) { + + int position = 0; + int sequence_length = 1; + + if( check_dollar && string[0] == '$' ) { + b->err |= BSON_FIELD_INIT_DOLLAR; + } + + while ( position < length ) { + if ( check_dot && *( string + position ) == '.' ) { + b->err |= BSON_FIELD_HAS_DOT; + } + + if ( check_utf8 ) { + sequence_length = trailingBytesForUTF8[*( string + position )] + 1; + if ( ( position + sequence_length ) > length ) { + b->err |= BSON_NOT_UTF8; + return BSON_ERROR; + } + if ( !isLegalUTF8( string + position, sequence_length ) ) { + b->err |= BSON_NOT_UTF8; + return BSON_ERROR; + } + } + position += sequence_length; + } + + return BSON_OK; +} + + +int bson_check_string( bson *b, const char *string, + const int length ) { + + return bson_validate_string( b, ( const unsigned char * )string, length, 1, 0, 0 ); +} + +int bson_check_field_name( bson *b, const char *string, + const int length ) { + + return bson_validate_string( b, ( const unsigned char * )string, length, 1, 1, 1 ); +}
\ No newline at end of file diff --git a/src/interface.c b/src/interface.c index 472fd9b..bb34c15 100644 --- a/src/interface.c +++ b/src/interface.c @@ -26,6 +26,7 @@ #include <pythonconsole.h> #endif #include <powdergraphics.h> +#include "save.h" SDLMod sdl_mod; int sdl_key, sdl_rkey, sdl_wheel, sdl_caps=0, sdl_ascii, sdl_zoom_trig=0; @@ -4265,7 +4266,7 @@ int open_ui(pixel *vid_buf, char *save_id, char *save_date) if (queue_open) { if (info_ready && data_ready) { // Do Open! - status = parse_save(data, data_size, 1, 0, 0, bmap, fvx, fvy, signs, parts, pmap); + status = parse_save(data, data_size, 1, 0, 0, bmap, vx, vy, pv, fvx, fvy, signs, parts, pmap); if (!status) { if(svf_last) free(svf_last); @@ -4827,7 +4828,7 @@ void execute_save(pixel *vid_buf) plens[0] = strlen(svf_name); uploadparts[1] = svf_description; plens[1] = strlen(svf_description); - uploadparts[2] = build_save(plens+2, 0, 0, XRES, YRES, bmap, fvx, fvy, signs, parts); + uploadparts[2] = build_save(plens+2, 0, 0, XRES, YRES, bmap, vx, vy, pv, fvx, fvy, signs, parts); uploadparts[3] = build_thumb(plens+3, 1); uploadparts[4] = (svf_publish==1)?"Public":"Private"; plens[4] = strlen((svf_publish==1)?"Public":"Private"); @@ -5945,9 +5946,12 @@ int save_filename_ui(pixel *vid_buf) pixel *save = NULL;//calloc((XRES/3)*(YRES/3), PIXELSIZE); ui_edit ed; - save_data = build_save(&save_size, 0, 0, XRES, YRES, bmap, fvx, fvy, signs, parts); + save_data = build_save(&save_size, 0, 0, XRES, YRES, bmap, vx, vy, pv, fvx, fvy, signs, parts); save_data_image = prerender_save(save_data, save_size, &imgw, &imgh); - save = resample_img(save_data_image, imgw, imgh, XRES/3, YRES/3); + if(save_data_image!=NULL) + { + save = resample_img(save_data_image, imgw, imgh, XRES/3, YRES/3); + } ed.x = x0+11; ed.y = y0+25; @@ -5993,7 +5997,10 @@ int save_filename_ui(pixel *vid_buf) drawrect(vid_buf, x0, y0, xsize, ysize, 192, 192, 192, 255); drawtext(vid_buf, x0+8, y0+8, "Filename:", 255, 255, 255, 255); drawrect(vid_buf, x0+8, y0+20, xsize-16, 16, 255, 255, 255, 180); - draw_image(vid_buf, save, x0+8, y0+40, XRES/3, YRES/3, 255); + if(save!=NULL) + { + draw_image(vid_buf, save, x0+8, y0+40, XRES/3, YRES/3, 255); + } drawrect(vid_buf, x0+8, y0+40, XRES/3, YRES/3, 192, 192, 192, 255); drawrect(vid_buf, x0, y0+ysize-16, xsize, 16, 192, 192, 192, 255); @@ -6204,7 +6211,7 @@ void catalogue_ui(pixel * vid_buf) void *data; data = file_load(csave->filename, &size); if(data){ - status = parse_save(data, size, 1, 0, 0, bmap, fvx, fvy, signs, parts, pmap); + status = parse_save(data, size, 1, 0, 0, bmap, vx, vy, pv, fvx, fvy, signs, parts, pmap); if(!status) { //svf_filename[0] = 0; @@ -60,6 +60,7 @@ #ifdef LUACONSOLE #include "luaconsole.h" #endif +#include "save.h" pixel *vid_buf; @@ -270,858 +271,6 @@ void dump_frame(pixel *src, int w, int h, int pitch) * STATE MANAGEMENT * ***********************************************************/ -void *build_thumb(int *size, int bzip2) -{ - unsigned char *d=calloc(1,XRES*YRES), *c; - int i,j,x,y; - for (i=0; i<NPART; i++) - if (parts[i].type) - { - x = (int)(parts[i].x+0.5f); - y = (int)(parts[i].y+0.5f); - if (x>=0 && x<XRES && y>=0 && y<YRES) - d[x+y*XRES] = parts[i].type; - } - for (y=0; y<YRES/CELL; y++) - for (x=0; x<XRES/CELL; x++) - if (bmap[y][x]) - for (j=0; j<CELL; j++) - for (i=0; i<CELL; i++) - d[x*CELL+i+(y*CELL+j)*XRES] = 0xFF; - j = XRES*YRES; - - if (bzip2) - { - i = (j*101+99)/100 + 608; - c = malloc(i); - - c[0] = 0x53; - c[1] = 0x68; - c[2] = 0x49; - c[3] = 0x74; - c[4] = PT_NUM; - c[5] = CELL; - c[6] = XRES/CELL; - c[7] = YRES/CELL; - - i -= 8; - - if (BZ2_bzBuffToBuffCompress((char *)(c+8), (unsigned *)&i, (char *)d, j, 9, 0, 0) != BZ_OK) - { - free(d); - free(c); - return NULL; - } - free(d); - *size = i+8; - return c; - } - - *size = j; - return d; -} - -//the saving function -void *build_save(int *size, int orig_x0, int orig_y0, int orig_w, int orig_h, unsigned char bmap[YRES/CELL][XRES/CELL], float fvx[YRES/CELL][XRES/CELL], float fvy[YRES/CELL][XRES/CELL], sign signs[MAXSIGNS], void* partsptr) -{ - unsigned char *d=calloc(1,3*(XRES/CELL)*(YRES/CELL)+(XRES*YRES)*15+MAXSIGNS*262), *c; - int i,j,x,y,p=0,*m=calloc(XRES*YRES, sizeof(int)); - int x0, y0, w, h, bx0=orig_x0/CELL, by0=orig_y0/CELL, bw, bh; - particle *parts = partsptr; - bw=(orig_w+orig_x0-bx0*CELL+CELL-1)/CELL; - bh=(orig_h+orig_y0-by0*CELL+CELL-1)/CELL; - - // normalize coordinates - x0 = bx0*CELL; - y0 = by0*CELL; - w = bw *CELL; - h = bh *CELL; - - // save the required air state - for (y=by0; y<by0+bh; y++) - for (x=bx0; x<bx0+bw; x++) - d[p++] = bmap[y][x]; - for (y=by0; y<by0+bh; y++) - for (x=bx0; x<bx0+bw; x++) - if (bmap[y][x]==WL_FAN||bmap[y][x]==4) - { - i = (int)(fvx[y][x]*64.0f+127.5f); - if (i<0) i=0; - if (i>255) i=255; - d[p++] = i; - } - for (y=by0; y<by0+bh; y++) - for (x=bx0; x<bx0+bw; x++) - if (bmap[y][x]==WL_FAN||bmap[y][x]==4) - { - i = (int)(fvy[y][x]*64.0f+127.5f); - if (i<0) i=0; - if (i>255) i=255; - d[p++] = i; - } - - // save the particle map - for (i=0; i<NPART; i++) - if (parts[i].type) - { - x = (int)(parts[i].x+0.5f); - y = (int)(parts[i].y+0.5f); - if (x>=orig_x0 && x<orig_x0+orig_w && y>=orig_y0 && y<orig_y0+orig_h) { - if (!m[(x-x0)+(y-y0)*w] || - parts[m[(x-x0)+(y-y0)*w]-1].type == PT_PHOT || - parts[m[(x-x0)+(y-y0)*w]-1].type == PT_NEUT) - m[(x-x0)+(y-y0)*w] = i+1; - } - } - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) - d[p++] = parts[i-1].type; - else - d[p++] = 0; - } - - // save particle properties - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) - { - i--; - x = (int)(parts[i].vx*16.0f+127.5f); - y = (int)(parts[i].vy*16.0f+127.5f); - if (x<0) x=0; - if (x>255) x=255; - if (y<0) y=0; - if (y>255) y=255; - d[p++] = x; - d[p++] = y; - } - } - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) { - //Everybody loves a 16bit int - //d[p++] = (parts[i-1].life+3)/4; - int ttlife = (int)parts[i-1].life; - d[p++] = ((ttlife&0xFF00)>>8); - d[p++] = (ttlife&0x00FF); - } - } - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) { - //Now saving tmp! - //d[p++] = (parts[i-1].life+3)/4; - int tttmp = (int)parts[i-1].tmp; - d[p++] = ((tttmp&0xFF00)>>8); - d[p++] = (tttmp&0x00FF); - } - } - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i && (parts[i-1].type==PT_PBCN)) { - //Save tmp2 - d[p++] = parts[i-1].tmp2; - } - } - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) { - //Save colour (ALPHA) - d[p++] = (parts[i-1].dcolour&0xFF000000)>>24; - } - } - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) { - //Save colour (RED) - d[p++] = (parts[i-1].dcolour&0x00FF0000)>>16; - } - } - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) { - //Save colour (GREEN) - d[p++] = (parts[i-1].dcolour&0x0000FF00)>>8; - } - } - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) { - //Save colour (BLUE) - d[p++] = (parts[i-1].dcolour&0x000000FF); - } - } - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) - { - //New Temperature saving uses a 16bit unsigned int for temperatures, giving a precision of 1 degree versus 36 for the old format - int tttemp = (int)parts[i-1].temp; - d[p++] = ((tttemp&0xFF00)>>8); - d[p++] = (tttemp&0x00FF); - } - } - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i && (parts[i-1].type==PT_CLNE || parts[i-1].type==PT_PCLN || parts[i-1].type==PT_BCLN || parts[i-1].type==PT_SPRK || parts[i-1].type==PT_LAVA || parts[i-1].type==PT_PIPE || parts[i-1].type==PT_LIFE || parts[i-1].type==PT_PBCN || parts[i-1].type==PT_WIRE || parts[i-1].type==PT_STOR || parts[i-1].type==PT_CONV)) - d[p++] = parts[i-1].ctype; - } - - j = 0; - for (i=0; i<MAXSIGNS; i++) - if (signs[i].text[0] && - signs[i].x>=x0 && signs[i].x<x0+w && - signs[i].y>=y0 && signs[i].y<y0+h) - j++; - d[p++] = j; - for (i=0; i<MAXSIGNS; i++) - if (signs[i].text[0] && - signs[i].x>=x0 && signs[i].x<x0+w && - signs[i].y>=y0 && signs[i].y<y0+h) - { - d[p++] = (signs[i].x-x0); - d[p++] = (signs[i].x-x0)>>8; - d[p++] = (signs[i].y-y0); - d[p++] = (signs[i].y-y0)>>8; - d[p++] = signs[i].ju; - x = strlen(signs[i].text); - d[p++] = x; - memcpy(d+p, signs[i].text, x); - p+=x; - } - - i = (p*101+99)/100 + 612; - c = malloc(i); - - //New file header uses PSv, replacing fuC. This is to detect if the client uses a new save format for temperatures - //This creates a problem for old clients, that display and "corrupt" error instead of a "newer version" error - - c[0] = 0x50; //0x66; - c[1] = 0x53; //0x75; - c[2] = 0x76; //0x43; - c[3] = legacy_enable|((sys_pause<<1)&0x02)|((gravityMode<<2)&0x0C)|((airMode<<4)&0x70)|((ngrav_enable<<7)&0x80); - c[4] = SAVE_VERSION; - c[5] = CELL; - c[6] = bw; - c[7] = bh; - c[8] = p; - c[9] = p >> 8; - c[10] = p >> 16; - c[11] = p >> 24; - - i -= 12; - - if (BZ2_bzBuffToBuffCompress((char *)(c+12), (unsigned *)&i, (char *)d, p, 9, 0, 0) != BZ_OK) - { - free(d); - free(c); - free(m); - return NULL; - } - free(d); - free(m); - - *size = i+12; - return c; -} - -int parse_save(void *save, int size, int replace, int x0, int y0, unsigned char bmap[YRES/CELL][XRES/CELL], float fvx[YRES/CELL][XRES/CELL], float fvy[YRES/CELL][XRES/CELL], sign signs[MAXSIGNS], void* partsptr, unsigned pmap[YRES][XRES]) -{ - unsigned char *d=NULL,*c=save; - int q,i,j,k,x,y,p=0,*m=NULL, ver, pty, ty, legacy_beta=0, tempGrav = 0; - int bx0=x0/CELL, by0=y0/CELL, bw, bh, w, h; - int nf=0, new_format = 0, ttv = 0; - particle *parts = partsptr; - int *fp = malloc(NPART*sizeof(int)); - - //New file header uses PSv, replacing fuC. This is to detect if the client uses a new save format for temperatures - //This creates a problem for old clients, that display and "corrupt" error instead of a "newer version" error - - if (size<16) - return 1; - if (!(c[2]==0x43 && c[1]==0x75 && c[0]==0x66) && !(c[2]==0x76 && c[1]==0x53 && c[0]==0x50)) - return 1; - if (c[2]==0x76 && c[1]==0x53 && c[0]==0x50) { - new_format = 1; - } - if (c[4]>SAVE_VERSION) - return 2; - ver = c[4]; - - if (ver<34) - { - legacy_enable = 1; - } - else - { - if (ver>=44) { - legacy_enable = c[3]&0x01; - if (!sys_pause) { - sys_pause = (c[3]>>1)&0x01; - } - if (ver>=46 && replace) { - gravityMode = ((c[3]>>2)&0x03);// | ((c[3]>>2)&0x01); - airMode = ((c[3]>>4)&0x07);// | ((c[3]>>4)&0x02) | ((c[3]>>4)&0x01); - } - if (ver>=49 && replace) { - tempGrav = ((c[3]>>7)&0x01); - } - } else { - if (c[3]==1||c[3]==0) { - legacy_enable = c[3]; - } else { - legacy_beta = 1; - } - } - } - - bw = c[6]; - bh = c[7]; - if (bx0+bw > XRES/CELL) - bx0 = XRES/CELL - bw; - if (by0+bh > YRES/CELL) - by0 = YRES/CELL - bh; - if (bx0 < 0) - bx0 = 0; - if (by0 < 0) - by0 = 0; - - if (c[5]!=CELL || bx0+bw>XRES/CELL || by0+bh>YRES/CELL) - return 3; - i = (unsigned)c[8]; - i |= ((unsigned)c[9])<<8; - i |= ((unsigned)c[10])<<16; - i |= ((unsigned)c[11])<<24; - d = malloc(i); - if (!d) - return 1; - - if (BZ2_bzBuffToBuffDecompress((char *)d, (unsigned *)&i, (char *)(c+12), size-12, 0, 0)) - return 1; - size = i; - - if (size < bw*bh) - return 1; - - // normalize coordinates - x0 = bx0*CELL; - y0 = by0*CELL; - w = bw *CELL; - h = bh *CELL; - - if (replace) - { - if (ver<46) { - gravityMode = 0; - airMode = 0; - } - clear_sim(); - } - parts_lastActiveIndex = NPART-1; - m = calloc(XRES*YRES, sizeof(int)); - - // make a catalog of free parts - //memset(pmap, 0, sizeof(pmap)); "Using sizeof for array given as function argument returns the size of pointer." - memset(pmap, 0, sizeof(unsigned)*(XRES*YRES)); - for (i=0; i<NPART; i++) - if (parts[i].type) - { - x = (int)(parts[i].x+0.5f); - y = (int)(parts[i].y+0.5f); - pmap[y][x] = (i<<8)|1; - } - else - fp[nf++] = i; - - // load the required air state - for (y=by0; y<by0+bh; y++) - for (x=bx0; x<bx0+bw; x++) - { - if (d[p]) - { - bmap[y][x] = d[p]; - if (bmap[y][x]==1) - bmap[y][x]=WL_WALL; - if (bmap[y][x]==2) - bmap[y][x]=WL_DESTROYALL; - if (bmap[y][x]==3) - bmap[y][x]=WL_ALLOWLIQUID; - if (bmap[y][x]==4) - bmap[y][x]=WL_FAN; - if (bmap[y][x]==5) - bmap[y][x]=WL_STREAM; - if (bmap[y][x]==6) - bmap[y][x]=WL_DETECT; - if (bmap[y][x]==7) - bmap[y][x]=WL_EWALL; - if (bmap[y][x]==8) - bmap[y][x]=WL_WALLELEC; - if (bmap[y][x]==9) - bmap[y][x]=WL_ALLOWAIR; - if (bmap[y][x]==10) - bmap[y][x]=WL_ALLOWSOLID; - if (bmap[y][x]==11) - bmap[y][x]=WL_ALLOWALLELEC; - if (bmap[y][x]==12) - bmap[y][x]=WL_EHOLE; - if (bmap[y][x]==13) - bmap[y][x]=WL_ALLOWGAS; - } - - p++; - } - for (y=by0; y<by0+bh; y++) - for (x=bx0; x<bx0+bw; x++) - if (d[(y-by0)*bw+(x-bx0)]==4||d[(y-by0)*bw+(x-bx0)]==WL_FAN) - { - if (p >= size) - goto corrupt; - fvx[y][x] = (d[p++]-127.0f)/64.0f; - } - for (y=by0; y<by0+bh; y++) - for (x=bx0; x<bx0+bw; x++) - if (d[(y-by0)*bw+(x-bx0)]==4||d[(y-by0)*bw+(x-bx0)]==WL_FAN) - { - if (p >= size) - goto corrupt; - fvy[y][x] = (d[p++]-127.0f)/64.0f; - } - - // load the particle map - i = 0; - pty = p; - for (y=y0; y<y0+h; y++) - for (x=x0; x<x0+w; x++) - { - if (p >= size) - goto corrupt; - j=d[p++]; - if (j >= PT_NUM) { - //TODO: Possibly some server side translation - j = PT_DUST;//goto corrupt; - } - gol[x][y]=0; - if (j) - { - if (pmap[y][x]) - { - k = pmap[y][x]>>8; - } - else if (i<nf) - { - k = fp[i]; - i++; - } - else - { - m[(x-x0)+(y-y0)*w] = NPART+1; - continue; - } - memset(parts+k, 0, sizeof(particle)); - parts[k].type = j; - if (j == PT_COAL) - parts[k].tmp = 50; - if (j == PT_FUSE) - parts[k].tmp = 50; - if (j == PT_PHOT) - parts[k].ctype = 0x3fffffff; - if (j == PT_SOAP) - parts[k].ctype = 0; - if (j==PT_BIZR || j==PT_BIZRG || j==PT_BIZRS) - parts[k].ctype = 0x47FFFF; - parts[k].x = (float)x; - parts[k].y = (float)y; - m[(x-x0)+(y-y0)*w] = k+1; - } - } - - // load particle properties - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) - { - i--; - if (p+1 >= size) - goto corrupt; - if (i < NPART) - { - parts[i].vx = (d[p++]-127.0f)/16.0f; - parts[i].vy = (d[p++]-127.0f)/16.0f; - } - else - p += 2; - } - } - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) - { - if (ver>=44) { - if (p >= size) { - goto corrupt; - } - if (i <= NPART) { - ttv = (d[p++])<<8; - ttv |= (d[p++]); - parts[i-1].life = ttv; - } else { - p+=2; - } - } else { - if (p >= size) - goto corrupt; - if (i <= NPART) - parts[i-1].life = d[p++]*4; - else - p++; - } - } - } - if (ver>=44) { - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) - { - if (p >= size) { - goto corrupt; - } - if (i <= NPART) { - ttv = (d[p++])<<8; - ttv |= (d[p++]); - parts[i-1].tmp = ttv; - if (ver<53 && !parts[i-1].tmp) - for (q = 1; q<=NGOLALT; q++) { - if (parts[i-1].type==goltype[q-1] && grule[q][9]==2) - parts[i-1].tmp = grule[q][9]-1; - } - if (ver>=51 && ver<53 && parts[i-1].type==PT_PBCN) - { - parts[i-1].tmp2 = parts[i-1].tmp; - parts[i-1].tmp = 0; - } - } else { - p+=2; - } - } - } - } - if (ver>=53) { - for (j=0; j<w*h; j++) - { - i = m[j]; - ty = d[pty+j]; - if (i && ty==PT_PBCN) - { - if (p >= size) - goto corrupt; - if (i <= NPART) - parts[i-1].tmp2 = d[p++]; - else - p++; - } - } - } - //Read ALPHA component - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) - { - if (ver>=49) { - if (p >= size) { - goto corrupt; - } - if (i <= NPART) { - parts[i-1].dcolour = d[p++]<<24; - } else { - p++; - } - } - } - } - //Read RED component - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) - { - if (ver>=49) { - if (p >= size) { - goto corrupt; - } - if (i <= NPART) { - parts[i-1].dcolour |= d[p++]<<16; - } else { - p++; - } - } - } - } - //Read GREEN component - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) - { - if (ver>=49) { - if (p >= size) { - goto corrupt; - } - if (i <= NPART) { - parts[i-1].dcolour |= d[p++]<<8; - } else { - p++; - } - } - } - } - //Read BLUE component - for (j=0; j<w*h; j++) - { - i = m[j]; - if (i) - { - if (ver>=49) { - if (p >= size) { - goto corrupt; - } - if (i <= NPART) { - parts[i-1].dcolour |= d[p++]; - } else { - p++; - } - } - } - } - for (j=0; j<w*h; j++) - { - i = m[j]; - ty = d[pty+j]; - if (i) - { - if (ver>=34&&legacy_beta==0) - { - if (p >= size) - { - goto corrupt; - } - if (i <= NPART) - { - if (ver>=42) { - if (new_format) { - ttv = (d[p++])<<8; - ttv |= (d[p++]); - if (parts[i-1].type==PT_PUMP) { - parts[i-1].temp = ttv + 0.15;//fix PUMP saved at 0, so that it loads at 0. - } else { - parts[i-1].temp = ttv; - } - } else { - parts[i-1].temp = (d[p++]*((MAX_TEMP+(-MIN_TEMP))/255))+MIN_TEMP; - } - } else { - parts[i-1].temp = ((d[p++]*((O_MAX_TEMP+(-O_MIN_TEMP))/255))+O_MIN_TEMP)+273; - } - } - else - { - p++; - if (new_format) { - p++; - } - } - } - else - { - parts[i-1].temp = ptypes[parts[i-1].type].heat; - } - } - } - for (j=0; j<w*h; j++) - { - int gnum = 0; - i = m[j]; - ty = d[pty+j]; - if (i && (ty==PT_CLNE || (ty==PT_PCLN && ver>=43) || (ty==PT_BCLN && ver>=44) || (ty==PT_SPRK && ver>=21) || (ty==PT_LAVA && ver>=34) || (ty==PT_PIPE && ver>=43) || (ty==PT_LIFE && ver>=51) || (ty==PT_PBCN && ver>=52) || (ty==PT_WIRE && ver>=55) || (ty==PT_STOR && ver>=59) || (ty==PT_CONV && ver>=60))) - { - if (p >= size) - goto corrupt; - if (i <= NPART) - parts[i-1].ctype = d[p++]; - else - p++; - } - // no more particle properties to load, so we can change type here without messing up loading - if (i && i<=NPART) - { - if ((player.spwn == 1 && ty==PT_STKM) || (player2.spwn == 1 && ty==PT_STKM2)) - { - parts[i-1].type = PT_NONE; - } - else if (parts[i-1].type == PT_STKM) - { - STKM_init_legs(&player, i-1); - player.spwn = 1; - player.elem = PT_DUST; - } - else if (parts[i-1].type == PT_STKM2) - { - STKM_init_legs(&player2, i-1); - player2.spwn = 1; - player2.elem = PT_DUST; - } - else if (parts[i-1].type == PT_FIGH) - { - unsigned char fcount = 0; - while (fcount < 100 && fcount < (fighcount+1) && fighters[fcount].spwn==1) fcount++; - if (fcount < 100 && fighters[fcount].spwn==0) - { - parts[i-1].tmp = fcount; - fighters[fcount].spwn = 1; - fighters[fcount].elem = PT_DUST; - fighcount++; - STKM_init_legs(&(fighters[fcount]), i-1); - } - } - - if (ver<48 && (ty==OLD_PT_WIND || (ty==PT_BRAY&&parts[i-1].life==0))) - { - // Replace invisible particles with something sensible and add decoration to hide it - x = (int)(parts[i-1].x+0.5f); - y = (int)(parts[i-1].y+0.5f); - parts[i-1].dcolour = 0xFF000000; - parts[i-1].type = PT_DMND; - } - if(ver<51 && ((ty>=78 && ty<=89) || (ty>=134 && ty<=146 && ty!=141))){ - //Replace old GOL - parts[i-1].type = PT_LIFE; - for (gnum = 0; gnum<NGOLALT; gnum++){ - if (ty==goltype[gnum]) - parts[i-1].ctype = gnum; - } - ty = PT_LIFE; - } - if(ver<52 && (ty==PT_CLNE || ty==PT_PCLN || ty==PT_BCLN)){ - //Replace old GOL ctypes in clone - for (gnum = 0; gnum<NGOLALT; gnum++){ - if (parts[i-1].ctype==goltype[gnum]) - { - parts[i-1].ctype = PT_LIFE; - parts[i-1].tmp = gnum; - } - } - } - if(ty==PT_LCRY){ - if(ver<67) - { - //New LCRY uses TMP not life - if(parts[i-1].life>=10) - { - parts[i-1].life = 10; - parts[i-1].tmp2 = 10; - parts[i-1].tmp = 3; - } - else if(parts[i-1].life<=0) - { - parts[i-1].life = 0; - parts[i-1].tmp2 = 0; - parts[i-1].tmp = 0; - } - else if(parts[i-1].life < 10 && parts[i-1].life > 0) - { - parts[i-1].tmp = 1; - } - } - else - { - parts[i-1].tmp2 = parts[i-1].life; - } - } - if (!ptypes[parts[i-1].type].enabled) - parts[i-1].type = PT_NONE; - } - } - - #ifndef RENDERER - //Change the gravity state - if(ngrav_enable != tempGrav && replace) - { - if(tempGrav) - start_grav_async(); - else - stop_grav_async(); - } - #endif - - gravity_mask(); - - if (p >= size) - goto version1; - j = d[p++]; - for (i=0; i<j; i++) - { - if (p+6 > size) - goto corrupt; - for (k=0; k<MAXSIGNS; k++) - if (!signs[k].text[0]) - break; - x = d[p++]; - x |= ((unsigned)d[p++])<<8; - if (k<MAXSIGNS) - signs[k].x = x+x0; - x = d[p++]; - x |= ((unsigned)d[p++])<<8; - if (k<MAXSIGNS) - signs[k].y = x+y0; - x = d[p++]; - if (k<MAXSIGNS) - signs[k].ju = x; - x = d[p++]; - if (p+x > size) - goto corrupt; - if (k<MAXSIGNS) - { - memcpy(signs[k].text, d+p, x); - signs[k].text[x] = 0; - clean_text(signs[k].text, 158-14 /* Current max sign length */); - } - p += x; - } - -version1: - if (m) free(m); - if (d) free(d); - if (fp) free(fp); - - return 0; - -corrupt: - if (m) free(m); - if (d) free(d); - if (fp) free(fp); - if (replace) - { - legacy_enable = 0; - clear_sim(); - } - return 1; -} - void clear_sim(void) { int i, x, y; @@ -1252,7 +401,7 @@ void stamp_save(int x, int y, int w, int h) FILE *f; int n; char fn[64], sn[16]; - void *s=build_save(&n, x, y, w, h, bmap, fvx, fvy, signs, parts); + void *s=build_save(&n, x, y, w, h, bmap, vx, vy, pv, fvx, fvy, signs, parts); #ifdef WIN32 _mkdir("stamps"); @@ -1489,7 +638,7 @@ int main(int argc, char *argv[]) if(load_data && load_size){ int parsestate = 0; //parsestate = parse_save(load_data, load_size, 1, 0, 0); - parsestate = parse_save(load_data, load_size, 1, 0, 0, bmap, fvx, fvy, signs, parts, pmap); + parsestate = parse_save(load_data, load_size, 1, 0, 0, bmap, vx, vy, pv, fvx, fvy, signs, parts, pmap); for(i=0; i<30; i++){ memset(vid_buf, 0, (XRES+BARSIZE)*YRES*PIXELSIZE); @@ -1632,7 +781,7 @@ int main(int argc, char *argv[]) { svf_last = file_data; svf_lsize = size; - if(!parse_save(file_data, size, 1, 0, 0, bmap, fvx, fvy, signs, parts, pmap)) + if(!parse_save(file_data, size, 1, 0, 0, bmap, fvx, fvy, vx, vy, pv, signs, parts, pmap)) { it=0; svf_filename[0] = 0; @@ -2876,7 +2025,7 @@ int main(int argc, char *argv[]) if (load_y<0) load_y=0; if (bq==1 && !b) { - parse_save(load_data, load_size, 0, load_x, load_y, bmap, fvx, fvy, signs, parts, pmap); + parse_save(load_data, load_size, 0, load_x, load_y, bmap, vx, vy, pv, fvx, fvy, signs, parts, pmap); free(load_data); free(load_img); load_mode = 0; @@ -2918,14 +2067,14 @@ int main(int argc, char *argv[]) { if (copy_mode==1)//CTRL-C, copy { - clipboard_data=build_save(&clipboard_length, save_x, save_y, save_w, save_h, bmap, fvx, fvy, signs, parts); + clipboard_data=build_save(&clipboard_length, save_x, save_y, save_w, save_h, bmap, vx, vy, pv, fvx, fvy, signs, parts); clipboard_ready = 1; save_mode = 0; copy_mode = 0; } else if (copy_mode==2)//CTRL-X, cut { - clipboard_data=build_save(&clipboard_length, save_x, save_y, save_w, save_h, bmap, fvx, fvy, signs, parts); + clipboard_data=build_save(&clipboard_length, save_x, save_y, save_w, save_h, bmap, vx, vy, pv, fvx, fvy, signs, parts); clipboard_ready = 1; save_mode = 0; copy_mode = 0; @@ -3061,7 +2210,7 @@ int main(int argc, char *argv[]) } if (x>=19 && x<=35 && svf_last && (svf_open || svf_fileopen) && !bq) { //int tpval = sys_pause; - parse_save(svf_last, svf_lsize, 1, 0, 0, bmap, fvx, fvy, signs, parts, pmap); + parse_save(svf_last, svf_lsize, 1, 0, 0, bmap, vx, vy, pv, fvx, fvy, signs, parts, pmap); //sys_pause = tpval; } if (x>=(XRES+BARSIZE-(510-476)) && x<=(XRES+BARSIZE-(510-491)) && !bq) diff --git a/src/save.c b/src/save.c new file mode 100644 index 0000000..6882979 --- /dev/null +++ b/src/save.c @@ -0,0 +1,1266 @@ +#include <bzlib.h> +#include "defines.h" +#include "powder.h" +#include "save.h" +#include "gravity.h" +#include "BSON.h" + +void *build_save(int *size, int orig_x0, int orig_y0, int orig_w, int orig_h, unsigned char bmap[YRES/CELL][XRES/CELL], float vx[YRES/CELL][XRES/CELL], float vy[YRES/CELL][XRES/CELL], float pv[YRES/CELL][XRES/CELL], float fvx[YRES/CELL][XRES/CELL], float fvy[YRES/CELL][XRES/CELL], sign signs[MAXSIGNS], void* partsptr) +{ + return build_save_OPS(size, orig_x0, orig_y0, orig_w, orig_h, bmap, vx, vy, pv, fvx, fvy, signs, partsptr); + //return build_save_PSv(size, orig_x0, orig_y0, orig_w, orig_h, bmap, fvx, fvy, signs, partsptr); +} + +int parse_save(void *save, int size, int replace, int x0, int y0, unsigned char bmap[YRES/CELL][XRES/CELL], float vx[YRES/CELL][XRES/CELL], float vy[YRES/CELL][XRES/CELL], float pv[YRES/CELL][XRES/CELL], float fvx[YRES/CELL][XRES/CELL], float fvy[YRES/CELL][XRES/CELL], sign signs[MAXSIGNS], void* partsptr, unsigned pmap[YRES][XRES]) +{ + unsigned char * saveData = save; + if(saveData[0] == 'O' && saveData[1] == 'P' && saveData[2] == 'S') + { + return parse_save_OPS(save, size, replace, x0, y0, bmap, vx, vy, pv, fvx, fvy, signs, partsptr, pmap); + } + else if((saveData[0]==0x66 && saveData[1]==0x75 && saveData[2]==0x43) || (saveData[0]==0x50 && saveData[1]==0x53 && saveData[2]==0x76)) + { + return parse_save_PSv(save, size, replace, x0, y0, bmap, fvx, fvy, signs, partsptr, pmap); + } +} + +void *build_save_OPS(int *size, int orig_x0, int orig_y0, int orig_w, int orig_h, unsigned char bmap[YRES/CELL][XRES/CELL], float vx[YRES/CELL][XRES/CELL], float vy[YRES/CELL][XRES/CELL], float pv[YRES/CELL][XRES/CELL], float fvx[YRES/CELL][XRES/CELL], float fvy[YRES/CELL][XRES/CELL], sign signs[MAXSIGNS], void* o_partsptr) +{ + particle *partsptr = o_partsptr; + unsigned char *partsData = NULL, *fanData = NULL, *wallData = NULL, *finalData = NULL, *outputData = NULL; + int partsDataLen, fanDataLen, wallDataLen, finalDataLen, outputDataLen; + int blockX, blockY, blockW, blockH, fullX, fullY, fullW, fullH; + int x, y, i, wallDataFound = 0; + + //Get coords in blocks + blockX = orig_x0/CELL; + blockY = orig_y0/CELL; + blockW = orig_w/CELL; + blockH = orig_h/CELL; + + //Snap full coords to block size + fullX = blockX*CELL; + fullY = blockY*CELL; + fullW = blockW*CELL; + fullH = blockH*CELL; + + //Copy fan and wall data + wallData = malloc(blockW*blockH); + wallDataLen = blockW*blockH; + fanData = malloc(blockW*blockH); + fanDataLen = 0; + for(x = blockX; x < blockX+blockW; x++) + { + for(y = blockY; y < blockY+blockH; y++) + { + wallData[y*blockW+x] = bmap[y][x]; + if(bmap[y][x] && !wallDataFound) + wallDataFound = 1; + if(bmap[y][x]==WL_FAN || bmap[y][x]==4) + { + i = (int)(fvy[y][x]*64.0f+127.5f); + if (i<0) i=0; + if (i>255) i=255; + fanData[fanDataLen++] = i; + } + } + } + if(!fanDataLen) + { + free(fanData); + fanData = NULL; + } + if(!wallDataFound) + { + free(wallData); + wallData = NULL; + } + + //Copy parts data + /* Field descriptor format: + | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | + | vy | vx | dcololour | ctype | tmp[2] | tmp[1] | life[2] | life[1] | + life[2] means a second byte (for a 16 bit field) if life[1] is present + */ + partsData = malloc(NPART * (sizeof(particle)+1)); + partsDataLen = 0; + for(i = 0; i < NPART; i++) + { + if(parts[i].type) + { + x = (int)(parts[i].x+0.5f); + y = (int)(parts[i].y+0.5f); + if(x >= fullX && x <= fullX+fullW && y >= fullY && y <= fullY+fullH) + { + unsigned char fieldDesc = 0; + int fieldDescLoc = 0, tempTemp, vTemp; + + //Type (required) + partsData[partsDataLen++] = partsptr[i].type; + + //X and Y coord (required), 2 bytes each + partsData[partsDataLen++] = x; + partsData[partsDataLen++] = x >> 8; + printf("Saved: %d, %d", (char)x, (char)(x>>8)); + partsData[partsDataLen++] = y; + partsData[partsDataLen++] = y >> 8; + + //Temperature (required), 2 bytes + tempTemp = partsptr[i].temp; + partsData[partsDataLen++] = tempTemp; + partsData[partsDataLen++] = tempTemp >> 8; + + //Location of the field descriptor + fieldDescLoc = partsDataLen++; + + //Life (optional), 1 to 2 bytes + if(partsptr[i].life) + { + fieldDesc |= 1; + partsData[partsDataLen++] = partsptr[i].life; + if(partsptr[i].life > 255) + { + fieldDesc |= 1 << 1; + partsData[partsDataLen++] = partsptr[i].life >> 8; + } + } + + //Tmp (optional), 1 to 2 bytes + if(partsptr[i].tmp) + { + fieldDesc |= 1 << 2; + partsData[partsDataLen++] = partsptr[i].tmp; + if(partsptr[i].tmp > 255) + { + fieldDesc |= 1 << 3; + partsData[partsDataLen++] = partsptr[i].tmp >> 8; + } + } + + //Ctype (optional), 1 byte + if(partsptr[i].ctype) + { + fieldDesc |= 1 << 4; + partsData[partsDataLen++] = partsptr[i].ctype; + } + + //Dcolour (optional), 4 bytes + if(partsptr[i].dcolour && (partsptr[i].dcolour & 0xFF000000)) + { + fieldDesc |= 1 << 5; + partsData[partsDataLen++] = (partsptr[i].dcolour&0xFF000000)>>24; + partsData[partsDataLen++] = (partsptr[i].dcolour&0x00FF0000)>>16; + partsData[partsDataLen++] = (partsptr[i].dcolour&0x0000FF00)>>8; + partsData[partsDataLen++] = (partsptr[i].dcolour&0x000000FF); + } + + //VX (optional), 1 byte + if(fabs(partsptr[i].vx) > 0.001f) + { + fieldDesc |= 1 << 6; + vTemp = (int)(partsptr[i].vx*16.0f+127.5f); + if (vTemp<0) vTemp=0; + if (vTemp>255) vTemp=255; + partsData[partsDataLen++] = vTemp; + } + + //VY (optional), 1 byte + if(fabs(partsptr[i].vy) > 0.001f) + { + fieldDesc |= 1 << 7; + vTemp = (int)(partsptr[i].vy*16.0f+127.5f); + if (vTemp<0) vTemp=0; + if (vTemp>255) vTemp=255; + partsData[partsDataLen++] = vTemp; + } + + //Write the field descriptor; + partsData[fieldDescLoc] = fieldDesc; + } + } + } + + bson b; + bson_init(&b); + /* These fields are in the "outer" header, don't bother saving here + bson_append_int(&b, "majorVersion", SAVE_VERSION); + bson_append_int(&b, "xRes", fullW); + bson_append_int(&b, "yRes", fullH); + bson_append_int(&b, "cellSize", CELL);*/ + //Save stuff like gravity, heat, blah states + bson_append_int(&b, "partsDataBytes", partsDataLen); //For debugging, remove eventually + if(partsData) + bson_append_binary(&b, "parts", BSON_BIN_USER, partsData, partsDataLen); + if(wallData) + bson_append_binary(&b, "wallMap", BSON_BIN_USER, wallData, wallDataLen); + if(fanData) + bson_append_binary(&b, "fanMap", BSON_BIN_USER, fanData, fanDataLen); + bson_finish(&b); + bson_print(&b); + + finalData = bson_data(&b); + finalDataLen = bson_size(&b); + outputDataLen = finalDataLen*2+12; + outputData = malloc(outputDataLen); + + outputData[0] = 'O'; + outputData[1] = 'P'; + outputData[2] = 'S'; + outputData[3] = '1'; + outputData[4] = SAVE_VERSION; + outputData[5] = CELL; + outputData[6] = blockW; + outputData[7] = blockH; + outputData[8] = finalDataLen; + outputData[9] = finalDataLen >> 8; + outputData[10] = finalDataLen >> 16; + outputData[11] = finalDataLen >> 24; + + if (BZ2_bzBuffToBuffCompress(outputData+12, &outputDataLen, finalData, bson_size(&b), 9, 0, 0) != BZ_OK) + { + puts("Save Error\n"); + free(outputData); + *size = 0; + outputData = NULL; + goto fin; + } + + *size = outputDataLen + 12; + +fin: + bson_destroy(&b); + if(partsData) + free(partsData); + if(wallData) + free(wallData); + if(fanData) + free(fanData); + + return outputData; +} + +int parse_save_OPS(void *save, int size, int replace, int x0, int y0, unsigned char bmap[YRES/CELL][XRES/CELL], float vx[YRES/CELL][XRES/CELL], float vy[YRES/CELL][XRES/CELL], float pv[YRES/CELL][XRES/CELL], float fvx[YRES/CELL][XRES/CELL], float fvy[YRES/CELL][XRES/CELL], sign signs[MAXSIGNS], void* o_partsptr, unsigned pmap[YRES][XRES]) +{ + particle *partsptr = o_partsptr; + unsigned char * inputData = save, *bsonData = NULL, *partsData = NULL, *fanData = NULL, *wallData = NULL; + int inputDataLen = size, bsonDataLen = 0, partsDataLen, fanDataLen, wallDataLen; + int i, freeIndicesCount, x, y, returnCode = 0; + int *freeIndices = NULL; + + bsonDataLen = ((unsigned)inputData[8]); + bsonDataLen |= ((unsigned)inputData[9]) << 8; + bsonDataLen |= ((unsigned)inputData[10]) << 16; + bsonDataLen |= ((unsigned)inputData[11]) << 24; + + bsonData = malloc(bsonDataLen); + if(!bsonData) + { + fprintf(stderr, "Internal error while parsing save: could not allocate buffer\n"); + return 3; + } + + if (BZ2_bzBuffToBuffDecompress(bsonData, &bsonDataLen, inputData+12, inputDataLen-12, 0, 0)) + return 1; + + bson b; + bson_iterator iter; + bson_init_data(&b, bsonData); + bson_iterator_init(&iter, &b); + while(bson_iterator_more(&iter)) + { + bson_iterator_next(&iter); + if(strcmp(bson_iterator_key(&iter), "parts")==0) + { + if(bson_iterator_type(&iter)==BSON_BINDATA && ((unsigned char)bson_iterator_bin_type(&iter))==BSON_BIN_USER && (partsDataLen = bson_iterator_bin_len(&iter)) > 0) + { + partsData = bson_iterator_bin_data(&iter); + } + else + { + fprintf(stderr, "Invalid datatype of particle data: %d[%d] %d[%d] %d[%d]\n", bson_iterator_type(&iter), bson_iterator_type(&iter)==BSON_BINDATA, (unsigned char)bson_iterator_bin_type(&iter), ((unsigned char)bson_iterator_bin_type(&iter))==BSON_BIN_USER, bson_iterator_bin_len(&iter), bson_iterator_bin_len(&iter)>0); + } + } + } + + //Read particle data + if(partsData) + { + int newIndex = 0, fieldDescriptor, tempTemp; + puts("Have particle data"); + parts_lastActiveIndex = NPART-1; + freeIndicesCount = 0; + freeIndices = calloc(sizeof(int), NPART); + for (i = 0; i<NPART; i++) + { + //Ensure ALL parts (even photons) are in the pmap so we can overwrite, keep a track of indices we can use + if (partsptr[i].type) + { + x = (int)(partsptr[i].x+0.5f); + y = (int)(partsptr[i].y+0.5f); + pmap[y][x] = (i<<8)|1; + } + else + freeIndices[freeIndicesCount++] = i; + } + i = 0; + //i+7 because we have 8 bytes of required fields (type (1), x (2), y (2), temp (2), descriptor (1)) + while(i+7 < partsDataLen) + { + x = partsData[i+1] | (((unsigned)partsData[i+2])<<8); + y = partsData[i+3] | (((unsigned)partsData[i+4])<<8); + fieldDescriptor = partsData[i+7]; + if(x >= XRES || x < 0 || y >= YRES || y < 0) + { + fprintf(stderr, "Out of range [%d]: %d %d, [%d, %d], [%d, %d]\n", i, x, y, (unsigned)partsData[i+1], (unsigned)partsData[i+2], (unsigned)partsData[i+3], (unsigned)partsData[i+4]); + goto fail; + } + if(partsData[i] > NPART) + partsData[i+1] = PT_DMND; //Replace all invalid powders with diamond + if(pmap[y][x]) + { + //Replace existing particle or allocated block + newIndex = pmap[y][x]>>8; + } + else if(freeIndicesCount) + { + //Create new particle + newIndex = freeIndices[--freeIndicesCount]; + } + else + { + //Nowhere to put new particle, tpt is sad :( + break; + } + if(newIndex < 0 || newIndex >= NPART) + goto fail; + + //Clear the particle, ready for our new properties + memset(&(partsptr[newIndex]), 0, sizeof(particle)); + + //Required fields + partsptr[newIndex].type = partsData[i]; + partsptr[newIndex].x = x; + partsptr[newIndex].y = y; + partsptr[newIndex].temp = (partsData[i+5] | (partsData[i+6]<<8)); + i+=8; + + //Read life + if(fieldDescriptor & 0x01) + { + if(i >= partsDataLen) goto fail; + partsptr[newIndex].life = partsData[i++]; + //Read 2nd byte + if(fieldDescriptor & 0x02) + { + if(i >= partsDataLen) goto fail; + partsptr[newIndex].life |= partsData[i++]; + } + } + + //Read tmp + if(fieldDescriptor & 0x04) + { + if(i >= partsDataLen) goto fail; + partsptr[newIndex].tmp = partsData[i++]; + //Read 2nd byte + if(fieldDescriptor & 0x08) + { + if(i >= partsDataLen) goto fail; + partsptr[newIndex].tmp |= partsData[i++]; + } + } + + //Read ctype + if(fieldDescriptor & 0x10) + { + if(i >= partsDataLen) goto fail; + partsptr[newIndex].ctype = partsData[i++]; + } + + //Read dcolour + if(fieldDescriptor & 0x20) + { + if(i+3 >= partsDataLen) goto fail; + partsptr[newIndex].dcolour = partsData[i++]; + partsptr[newIndex].dcolour = partsData[i++]; + partsptr[newIndex].dcolour = partsData[i++]; + partsptr[newIndex].dcolour = partsData[i++]; + } + + //Read vx + if(fieldDescriptor & 0x40) + { + if(i >= partsDataLen) goto fail; + partsptr[newIndex].vx = (partsData[i++]-127.0f)/16.0f; + } + + //Read vy + if(fieldDescriptor & 0x80) + { + if(i >= partsDataLen) goto fail; + partsptr[newIndex].vy = (partsData[i++]-127.0f)/16.0f; + } + } + } + goto fin; +fail: + //Clean up everything + returnCode = 1; +fin: + bson_destroy(&b); + if(freeIndices) + free(freeIndices); + return returnCode; +} + +//the old saving function +void *build_save_PSv(int *size, int orig_x0, int orig_y0, int orig_w, int orig_h, unsigned char bmap[YRES/CELL][XRES/CELL], float fvx[YRES/CELL][XRES/CELL], float fvy[YRES/CELL][XRES/CELL], sign signs[MAXSIGNS], void* partsptr) +{ + unsigned char *d=calloc(1,3*(XRES/CELL)*(YRES/CELL)+(XRES*YRES)*15+MAXSIGNS*262), *c; + int i,j,x,y,p=0,*m=calloc(XRES*YRES, sizeof(int)); + int x0, y0, w, h, bx0=orig_x0/CELL, by0=orig_y0/CELL, bw, bh; + particle *parts = partsptr; + bw=(orig_w+orig_x0-bx0*CELL+CELL-1)/CELL; + bh=(orig_h+orig_y0-by0*CELL+CELL-1)/CELL; + + // normalize coordinates + x0 = bx0*CELL; + y0 = by0*CELL; + w = bw *CELL; + h = bh *CELL; + + // save the required air state + for (y=by0; y<by0+bh; y++) + for (x=bx0; x<bx0+bw; x++) + d[p++] = bmap[y][x]; + for (y=by0; y<by0+bh; y++) + for (x=bx0; x<bx0+bw; x++) + if (bmap[y][x]==WL_FAN||bmap[y][x]==4) + { + i = (int)(fvx[y][x]*64.0f+127.5f); + if (i<0) i=0; + if (i>255) i=255; + d[p++] = i; + } + for (y=by0; y<by0+bh; y++) + for (x=bx0; x<bx0+bw; x++) + if (bmap[y][x]==WL_FAN||bmap[y][x]==4) + { + i = (int)(fvy[y][x]*64.0f+127.5f); + if (i<0) i=0; + if (i>255) i=255; + d[p++] = i; + } + + // save the particle map + for (i=0; i<NPART; i++) + if (parts[i].type) + { + x = (int)(parts[i].x+0.5f); + y = (int)(parts[i].y+0.5f); + if (x>=orig_x0 && x<orig_x0+orig_w && y>=orig_y0 && y<orig_y0+orig_h) { + if (!m[(x-x0)+(y-y0)*w] || + parts[m[(x-x0)+(y-y0)*w]-1].type == PT_PHOT || + parts[m[(x-x0)+(y-y0)*w]-1].type == PT_NEUT) + m[(x-x0)+(y-y0)*w] = i+1; + } + } + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) + d[p++] = parts[i-1].type; + else + d[p++] = 0; + } + + // save particle properties + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) + { + i--; + x = (int)(parts[i].vx*16.0f+127.5f); + y = (int)(parts[i].vy*16.0f+127.5f); + if (x<0) x=0; + if (x>255) x=255; + if (y<0) y=0; + if (y>255) y=255; + d[p++] = x; + d[p++] = y; + } + } + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) { + //Everybody loves a 16bit int + //d[p++] = (parts[i-1].life+3)/4; + int ttlife = (int)parts[i-1].life; + d[p++] = ((ttlife&0xFF00)>>8); + d[p++] = (ttlife&0x00FF); + } + } + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) { + //Now saving tmp! + //d[p++] = (parts[i-1].life+3)/4; + int tttmp = (int)parts[i-1].tmp; + d[p++] = ((tttmp&0xFF00)>>8); + d[p++] = (tttmp&0x00FF); + } + } + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i && (parts[i-1].type==PT_PBCN)) { + //Save tmp2 + d[p++] = parts[i-1].tmp2; + } + } + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) { + //Save colour (ALPHA) + d[p++] = (parts[i-1].dcolour&0xFF000000)>>24; + } + } + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) { + //Save colour (RED) + d[p++] = (parts[i-1].dcolour&0x00FF0000)>>16; + } + } + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) { + //Save colour (GREEN) + d[p++] = (parts[i-1].dcolour&0x0000FF00)>>8; + } + } + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) { + //Save colour (BLUE) + d[p++] = (parts[i-1].dcolour&0x000000FF); + } + } + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) + { + //New Temperature saving uses a 16bit unsigned int for temperatures, giving a precision of 1 degree versus 36 for the old format + int tttemp = (int)parts[i-1].temp; + d[p++] = ((tttemp&0xFF00)>>8); + d[p++] = (tttemp&0x00FF); + } + } + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i && (parts[i-1].type==PT_CLNE || parts[i-1].type==PT_PCLN || parts[i-1].type==PT_BCLN || parts[i-1].type==PT_SPRK || parts[i-1].type==PT_LAVA || parts[i-1].type==PT_PIPE || parts[i-1].type==PT_LIFE || parts[i-1].type==PT_PBCN || parts[i-1].type==PT_WIRE || parts[i-1].type==PT_STOR || parts[i-1].type==PT_CONV)) + d[p++] = parts[i-1].ctype; + } + + j = 0; + for (i=0; i<MAXSIGNS; i++) + if (signs[i].text[0] && + signs[i].x>=x0 && signs[i].x<x0+w && + signs[i].y>=y0 && signs[i].y<y0+h) + j++; + d[p++] = j; + for (i=0; i<MAXSIGNS; i++) + if (signs[i].text[0] && + signs[i].x>=x0 && signs[i].x<x0+w && + signs[i].y>=y0 && signs[i].y<y0+h) + { + d[p++] = (signs[i].x-x0); + d[p++] = (signs[i].x-x0)>>8; + d[p++] = (signs[i].y-y0); + d[p++] = (signs[i].y-y0)>>8; + d[p++] = signs[i].ju; + x = strlen(signs[i].text); + d[p++] = x; + memcpy(d+p, signs[i].text, x); + p+=x; + } + + i = (p*101+99)/100 + 612; + c = malloc(i); + + //New file header uses PSv, replacing fuC. This is to detect if the client uses a new save format for temperatures + //This creates a problem for old clients, that display and "corrupt" error instead of a "newer version" error + + c[0] = 0x50; //0x66; + c[1] = 0x53; //0x75; + c[2] = 0x76; //0x43; + c[3] = legacy_enable|((sys_pause<<1)&0x02)|((gravityMode<<2)&0x0C)|((airMode<<4)&0x70)|((ngrav_enable<<7)&0x80); + c[4] = SAVE_VERSION; + c[5] = CELL; + c[6] = bw; + c[7] = bh; + c[8] = p; + c[9] = p >> 8; + c[10] = p >> 16; + c[11] = p >> 24; + + i -= 12; + + if (BZ2_bzBuffToBuffCompress((char *)(c+12), (unsigned *)&i, (char *)d, p, 9, 0, 0) != BZ_OK) + { + free(d); + free(c); + free(m); + return NULL; + } + free(d); + free(m); + + *size = i+12; + return c; +} + +int parse_save_PSv(void *save, int size, int replace, int x0, int y0, unsigned char bmap[YRES/CELL][XRES/CELL], float fvx[YRES/CELL][XRES/CELL], float fvy[YRES/CELL][XRES/CELL], sign signs[MAXSIGNS], void* partsptr, unsigned pmap[YRES][XRES]) +{ + unsigned char *d=NULL,*c=save; + int q,i,j,k,x,y,p=0,*m=NULL, ver, pty, ty, legacy_beta=0, tempGrav = 0; + int bx0=x0/CELL, by0=y0/CELL, bw, bh, w, h; + int nf=0, new_format = 0, ttv = 0; + particle *parts = partsptr; + int *fp = malloc(NPART*sizeof(int)); + + //New file header uses PSv, replacing fuC. This is to detect if the client uses a new save format for temperatures + //This creates a problem for old clients, that display and "corrupt" error instead of a "newer version" error + + if (size<16) + return 1; + if (!(c[2]==0x43 && c[1]==0x75 && c[0]==0x66) && !(c[2]==0x76 && c[1]==0x53 && c[0]==0x50)) + return 1; + if (c[2]==0x76 && c[1]==0x53 && c[0]==0x50) { + new_format = 1; + } + if (c[4]>SAVE_VERSION) + return 2; + ver = c[4]; + + if (ver<34) + { + legacy_enable = 1; + } + else + { + if (ver>=44) { + legacy_enable = c[3]&0x01; + if (!sys_pause) { + sys_pause = (c[3]>>1)&0x01; + } + if (ver>=46 && replace) { + gravityMode = ((c[3]>>2)&0x03);// | ((c[3]>>2)&0x01); + airMode = ((c[3]>>4)&0x07);// | ((c[3]>>4)&0x02) | ((c[3]>>4)&0x01); + } + if (ver>=49 && replace) { + tempGrav = ((c[3]>>7)&0x01); + } + } else { + if (c[3]==1||c[3]==0) { + legacy_enable = c[3]; + } else { + legacy_beta = 1; + } + } + } + + bw = c[6]; + bh = c[7]; + if (bx0+bw > XRES/CELL) + bx0 = XRES/CELL - bw; + if (by0+bh > YRES/CELL) + by0 = YRES/CELL - bh; + if (bx0 < 0) + bx0 = 0; + if (by0 < 0) + by0 = 0; + + if (c[5]!=CELL || bx0+bw>XRES/CELL || by0+bh>YRES/CELL) + return 3; + i = (unsigned)c[8]; + i |= ((unsigned)c[9])<<8; + i |= ((unsigned)c[10])<<16; + i |= ((unsigned)c[11])<<24; + d = malloc(i); + if (!d) + return 1; + + if (BZ2_bzBuffToBuffDecompress((char *)d, (unsigned *)&i, (char *)(c+12), size-12, 0, 0)) + return 1; + size = i; + + if (size < bw*bh) + return 1; + + // normalize coordinates + x0 = bx0*CELL; + y0 = by0*CELL; + w = bw *CELL; + h = bh *CELL; + + if (replace) + { + if (ver<46) { + gravityMode = 0; + airMode = 0; + } + clear_sim(); + } + parts_lastActiveIndex = NPART-1; + m = calloc(XRES*YRES, sizeof(int)); + + // make a catalog of free parts + //memset(pmap, 0, sizeof(pmap)); "Using sizeof for array given as function argument returns the size of pointer." + memset(pmap, 0, sizeof(unsigned)*(XRES*YRES)); + for (i=0; i<NPART; i++) + if (parts[i].type) + { + x = (int)(parts[i].x+0.5f); + y = (int)(parts[i].y+0.5f); + pmap[y][x] = (i<<8)|1; + } + else + fp[nf++] = i; + + // load the required air state + for (y=by0; y<by0+bh; y++) + for (x=bx0; x<bx0+bw; x++) + { + if (d[p]) + { + bmap[y][x] = d[p]; + if (bmap[y][x]==1) + bmap[y][x]=WL_WALL; + if (bmap[y][x]==2) + bmap[y][x]=WL_DESTROYALL; + if (bmap[y][x]==3) + bmap[y][x]=WL_ALLOWLIQUID; + if (bmap[y][x]==4) + bmap[y][x]=WL_FAN; + if (bmap[y][x]==5) + bmap[y][x]=WL_STREAM; + if (bmap[y][x]==6) + bmap[y][x]=WL_DETECT; + if (bmap[y][x]==7) + bmap[y][x]=WL_EWALL; + if (bmap[y][x]==8) + bmap[y][x]=WL_WALLELEC; + if (bmap[y][x]==9) + bmap[y][x]=WL_ALLOWAIR; + if (bmap[y][x]==10) + bmap[y][x]=WL_ALLOWSOLID; + if (bmap[y][x]==11) + bmap[y][x]=WL_ALLOWALLELEC; + if (bmap[y][x]==12) + bmap[y][x]=WL_EHOLE; + if (bmap[y][x]==13) + bmap[y][x]=WL_ALLOWGAS; + } + + p++; + } + for (y=by0; y<by0+bh; y++) + for (x=bx0; x<bx0+bw; x++) + if (d[(y-by0)*bw+(x-bx0)]==4||d[(y-by0)*bw+(x-bx0)]==WL_FAN) + { + if (p >= size) + goto corrupt; + fvx[y][x] = (d[p++]-127.0f)/64.0f; + } + for (y=by0; y<by0+bh; y++) + for (x=bx0; x<bx0+bw; x++) + if (d[(y-by0)*bw+(x-bx0)]==4||d[(y-by0)*bw+(x-bx0)]==WL_FAN) + { + if (p >= size) + goto corrupt; + fvy[y][x] = (d[p++]-127.0f)/64.0f; + } + + // load the particle map + i = 0; + pty = p; + for (y=y0; y<y0+h; y++) + for (x=x0; x<x0+w; x++) + { + if (p >= size) + goto corrupt; + j=d[p++]; + if (j >= PT_NUM) { + //TODO: Possibly some server side translation + j = PT_DUST;//goto corrupt; + } + gol[x][y]=0; + if (j) + { + if (pmap[y][x]) + { + k = pmap[y][x]>>8; + } + else if (i<nf) + { + k = fp[i]; + i++; + } + else + { + m[(x-x0)+(y-y0)*w] = NPART+1; + continue; + } + memset(parts+k, 0, sizeof(particle)); + parts[k].type = j; + if (j == PT_COAL) + parts[k].tmp = 50; + if (j == PT_FUSE) + parts[k].tmp = 50; + if (j == PT_PHOT) + parts[k].ctype = 0x3fffffff; + if (j == PT_SOAP) + parts[k].ctype = 0; + if (j==PT_BIZR || j==PT_BIZRG || j==PT_BIZRS) + parts[k].ctype = 0x47FFFF; + parts[k].x = (float)x; + parts[k].y = (float)y; + m[(x-x0)+(y-y0)*w] = k+1; + } + } + + // load particle properties + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) + { + i--; + if (p+1 >= size) + goto corrupt; + if (i < NPART) + { + parts[i].vx = (d[p++]-127.0f)/16.0f; + parts[i].vy = (d[p++]-127.0f)/16.0f; + } + else + p += 2; + } + } + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) + { + if (ver>=44) { + if (p >= size) { + goto corrupt; + } + if (i <= NPART) { + ttv = (d[p++])<<8; + ttv |= (d[p++]); + parts[i-1].life = ttv; + } else { + p+=2; + } + } else { + if (p >= size) + goto corrupt; + if (i <= NPART) + parts[i-1].life = d[p++]*4; + else + p++; + } + } + } + if (ver>=44) { + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) + { + if (p >= size) { + goto corrupt; + } + if (i <= NPART) { + ttv = (d[p++])<<8; + ttv |= (d[p++]); + parts[i-1].tmp = ttv; + if (ver<53 && !parts[i-1].tmp) + for (q = 1; q<=NGOLALT; q++) { + if (parts[i-1].type==goltype[q-1] && grule[q][9]==2) + parts[i-1].tmp = grule[q][9]-1; + } + if (ver>=51 && ver<53 && parts[i-1].type==PT_PBCN) + { + parts[i-1].tmp2 = parts[i-1].tmp; + parts[i-1].tmp = 0; + } + } else { + p+=2; + } + } + } + } + if (ver>=53) { + for (j=0; j<w*h; j++) + { + i = m[j]; + ty = d[pty+j]; + if (i && ty==PT_PBCN) + { + if (p >= size) + goto corrupt; + if (i <= NPART) + parts[i-1].tmp2 = d[p++]; + else + p++; + } + } + } + //Read ALPHA component + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) + { + if (ver>=49) { + if (p >= size) { + goto corrupt; + } + if (i <= NPART) { + parts[i-1].dcolour = d[p++]<<24; + } else { + p++; + } + } + } + } + //Read RED component + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) + { + if (ver>=49) { + if (p >= size) { + goto corrupt; + } + if (i <= NPART) { + parts[i-1].dcolour |= d[p++]<<16; + } else { + p++; + } + } + } + } + //Read GREEN component + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) + { + if (ver>=49) { + if (p >= size) { + goto corrupt; + } + if (i <= NPART) { + parts[i-1].dcolour |= d[p++]<<8; + } else { + p++; + } + } + } + } + //Read BLUE component + for (j=0; j<w*h; j++) + { + i = m[j]; + if (i) + { + if (ver>=49) { + if (p >= size) { + goto corrupt; + } + if (i <= NPART) { + parts[i-1].dcolour |= d[p++]; + } else { + p++; + } + } + } + } + for (j=0; j<w*h; j++) + { + i = m[j]; + ty = d[pty+j]; + if (i) + { + if (ver>=34&&legacy_beta==0) + { + if (p >= size) + { + goto corrupt; + } + if (i <= NPART) + { + if (ver>=42) { + if (new_format) { + ttv = (d[p++])<<8; + ttv |= (d[p++]); + if (parts[i-1].type==PT_PUMP) { + parts[i-1].temp = ttv + 0.15;//fix PUMP saved at 0, so that it loads at 0. + } else { + parts[i-1].temp = ttv; + } + } else { + parts[i-1].temp = (d[p++]*((MAX_TEMP+(-MIN_TEMP))/255))+MIN_TEMP; + } + } else { + parts[i-1].temp = ((d[p++]*((O_MAX_TEMP+(-O_MIN_TEMP))/255))+O_MIN_TEMP)+273; + } + } + else + { + p++; + if (new_format) { + p++; + } + } + } + else + { + parts[i-1].temp = ptypes[parts[i-1].type].heat; + } + } + } + for (j=0; j<w*h; j++) + { + int gnum = 0; + i = m[j]; + ty = d[pty+j]; + if (i && (ty==PT_CLNE || (ty==PT_PCLN && ver>=43) || (ty==PT_BCLN && ver>=44) || (ty==PT_SPRK && ver>=21) || (ty==PT_LAVA && ver>=34) || (ty==PT_PIPE && ver>=43) || (ty==PT_LIFE && ver>=51) || (ty==PT_PBCN && ver>=52) || (ty==PT_WIRE && ver>=55) || (ty==PT_STOR && ver>=59) || (ty==PT_CONV && ver>=60))) + { + if (p >= size) + goto corrupt; + if (i <= NPART) + parts[i-1].ctype = d[p++]; + else + p++; + } + // no more particle properties to load, so we can change type here without messing up loading + if (i && i<=NPART) + { + if ((player.spwn == 1 && ty==PT_STKM) || (player2.spwn == 1 && ty==PT_STKM2)) + { + parts[i-1].type = PT_NONE; + } + else if (parts[i-1].type == PT_STKM) + { + STKM_init_legs(&player, i-1); + player.spwn = 1; + player.elem = PT_DUST; + } + else if (parts[i-1].type == PT_STKM2) + { + STKM_init_legs(&player2, i-1); + player2.spwn = 1; + player2.elem = PT_DUST; + } + else if (parts[i-1].type == PT_FIGH) + { + unsigned char fcount = 0; + while (fcount < 100 && fcount < (fighcount+1) && fighters[fcount].spwn==1) fcount++; + if (fcount < 100 && fighters[fcount].spwn==0) + { + parts[i-1].tmp = fcount; + fighters[fcount].spwn = 1; + fighters[fcount].elem = PT_DUST; + fighcount++; + STKM_init_legs(&(fighters[fcount]), i-1); + } + } + + if (ver<48 && (ty==OLD_PT_WIND || (ty==PT_BRAY&&parts[i-1].life==0))) + { + // Replace invisible particles with something sensible and add decoration to hide it + x = (int)(parts[i-1].x+0.5f); + y = (int)(parts[i-1].y+0.5f); + parts[i-1].dcolour = 0xFF000000; + parts[i-1].type = PT_DMND; + } + if(ver<51 && ((ty>=78 && ty<=89) || (ty>=134 && ty<=146 && ty!=141))){ + //Replace old GOL + parts[i-1].type = PT_LIFE; + for (gnum = 0; gnum<NGOLALT; gnum++){ + if (ty==goltype[gnum]) + parts[i-1].ctype = gnum; + } + ty = PT_LIFE; + } + if(ver<52 && (ty==PT_CLNE || ty==PT_PCLN || ty==PT_BCLN)){ + //Replace old GOL ctypes in clone + for (gnum = 0; gnum<NGOLALT; gnum++){ + if (parts[i-1].ctype==goltype[gnum]) + { + parts[i-1].ctype = PT_LIFE; + parts[i-1].tmp = gnum; + } + } + } + if(ty==PT_LCRY){ + if(ver<67) + { + //New LCRY uses TMP not life + if(parts[i-1].life>=10) + { + parts[i-1].life = 10; + parts[i-1].tmp2 = 10; + parts[i-1].tmp = 3; + } + else if(parts[i-1].life<=0) + { + parts[i-1].life = 0; + parts[i-1].tmp2 = 0; + parts[i-1].tmp = 0; + } + else if(parts[i-1].life < 10 && parts[i-1].life > 0) + { + parts[i-1].tmp = 1; + } + } + else + { + parts[i-1].tmp2 = parts[i-1].life; + } + } + if (!ptypes[parts[i-1].type].enabled) + parts[i-1].type = PT_NONE; + } + } + + #ifndef RENDERER + //Change the gravity state + if(ngrav_enable != tempGrav && replace) + { + if(tempGrav) + start_grav_async(); + else + stop_grav_async(); + } + #endif + + gravity_mask(); + + if (p >= size) + goto version1; + j = d[p++]; + for (i=0; i<j; i++) + { + if (p+6 > size) + goto corrupt; + for (k=0; k<MAXSIGNS; k++) + if (!signs[k].text[0]) + break; + x = d[p++]; + x |= ((unsigned)d[p++])<<8; + if (k<MAXSIGNS) + signs[k].x = x+x0; + x = d[p++]; + x |= ((unsigned)d[p++])<<8; + if (k<MAXSIGNS) + signs[k].y = x+y0; + x = d[p++]; + if (k<MAXSIGNS) + signs[k].ju = x; + x = d[p++]; + if (p+x > size) + goto corrupt; + if (k<MAXSIGNS) + { + memcpy(signs[k].text, d+p, x); + signs[k].text[x] = 0; + clean_text(signs[k].text, 158-14 /* Current max sign length */); + } + p += x; + } + +version1: + if (m) free(m); + if (d) free(d); + if (fp) free(fp); + + return 0; + +corrupt: + if (m) free(m); + if (d) free(d); + if (fp) free(fp); + if (replace) + { + legacy_enable = 0; + clear_sim(); + } + return 1; +} + +void *build_thumb(int *size, int bzip2) +{ + unsigned char *d=calloc(1,XRES*YRES), *c; + int i,j,x,y; + for (i=0; i<NPART; i++) + if (parts[i].type) + { + x = (int)(parts[i].x+0.5f); + y = (int)(parts[i].y+0.5f); + if (x>=0 && x<XRES && y>=0 && y<YRES) + d[x+y*XRES] = parts[i].type; + } + for (y=0; y<YRES/CELL; y++) + for (x=0; x<XRES/CELL; x++) + if (bmap[y][x]) + for (j=0; j<CELL; j++) + for (i=0; i<CELL; i++) + d[x*CELL+i+(y*CELL+j)*XRES] = 0xFF; + j = XRES*YRES; + + if (bzip2) + { + i = (j*101+99)/100 + 608; + c = malloc(i); + + c[0] = 0x53; + c[1] = 0x68; + c[2] = 0x49; + c[3] = 0x74; + c[4] = PT_NUM; + c[5] = CELL; + c[6] = XRES/CELL; + c[7] = YRES/CELL; + + i -= 8; + + if (BZ2_bzBuffToBuffCompress((char *)(c+8), (unsigned *)&i, (char *)d, j, 9, 0, 0) != BZ_OK) + { + free(d); + free(c); + return NULL; + } + free(d); + *size = i+8; + return c; + } + + *size = j; + return d; +}
\ No newline at end of file |
