From 86369670aaa11b8cd2ddcbd46413fb9482e4e58f Mon Sep 17 00:00:00 2001 From: Simon Robertshaw Date: Fri, 30 Dec 2011 02:06:31 +0000 Subject: [PATCH] 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?) --- includes/BSON.h | 1199 +++++++++++++++++++++++++++++++++++++++++ includes/defines.h | 9 +- includes/save.h | 19 + src/BSON.c | 1122 +++++++++++++++++++++++++++++++++++++++ src/interface.c | 19 +- src/main.c | 867 +----------------------------- src/save.c | 1266 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 3633 insertions(+), 868 deletions(-) create mode 100644 includes/BSON.h create mode 100644 includes/save.h create mode 100644 src/BSON.c create mode 100644 src/save.c diff --git a/includes/BSON.h b/includes/BSON.h new file mode 100644 index 000000000..f3222552b --- /dev/null +++ b/includes/BSON.h @@ -0,0 +1,1199 @@ +/** + * @file bson.h + * @brief BSON Declarations + */ + +/* 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. + */ + +#ifndef _BSON_H_ +#define _BSON_H_ + +#include +#include +#include +#include +#include +#include "defines.h" + +typedef long long int int64_t; +typedef unsigned long long int uint64_t; + +#define BSON_OK 0 +#define BSON_ERROR -1 + +static const char bson_numstrs[1000][4] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", + "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", + "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", + "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", + "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", + "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", + "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", + "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", + "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", + + "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", + "110", "111", "112", "113", "114", "115", "116", "117", "118", "119", + "120", "121", "122", "123", "124", "125", "126", "127", "128", "129", + "130", "131", "132", "133", "134", "135", "136", "137", "138", "139", + "140", "141", "142", "143", "144", "145", "146", "147", "148", "149", + "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", + "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", + "170", "171", "172", "173", "174", "175", "176", "177", "178", "179", + "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", + "190", "191", "192", "193", "194", "195", "196", "197", "198", "199", + + "200", "201", "202", "203", "204", "205", "206", "207", "208", "209", + "210", "211", "212", "213", "214", "215", "216", "217", "218", "219", + "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", + "230", "231", "232", "233", "234", "235", "236", "237", "238", "239", + "240", "241", "242", "243", "244", "245", "246", "247", "248", "249", + "250", "251", "252", "253", "254", "255", "256", "257", "258", "259", + "260", "261", "262", "263", "264", "265", "266", "267", "268", "269", + "270", "271", "272", "273", "274", "275", "276", "277", "278", "279", + "280", "281", "282", "283", "284", "285", "286", "287", "288", "289", + "290", "291", "292", "293", "294", "295", "296", "297", "298", "299", + + "300", "301", "302", "303", "304", "305", "306", "307", "308", "309", + "310", "311", "312", "313", "314", "315", "316", "317", "318", "319", + "320", "321", "322", "323", "324", "325", "326", "327", "328", "329", + "330", "331", "332", "333", "334", "335", "336", "337", "338", "339", + "340", "341", "342", "343", "344", "345", "346", "347", "348", "349", + "350", "351", "352", "353", "354", "355", "356", "357", "358", "359", + "360", "361", "362", "363", "364", "365", "366", "367", "368", "369", + "370", "371", "372", "373", "374", "375", "376", "377", "378", "379", + "380", "381", "382", "383", "384", "385", "386", "387", "388", "389", + "390", "391", "392", "393", "394", "395", "396", "397", "398", "399", + + "400", "401", "402", "403", "404", "405", "406", "407", "408", "409", + "410", "411", "412", "413", "414", "415", "416", "417", "418", "419", + "420", "421", "422", "423", "424", "425", "426", "427", "428", "429", + "430", "431", "432", "433", "434", "435", "436", "437", "438", "439", + "440", "441", "442", "443", "444", "445", "446", "447", "448", "449", + "450", "451", "452", "453", "454", "455", "456", "457", "458", "459", + "460", "461", "462", "463", "464", "465", "466", "467", "468", "469", + "470", "471", "472", "473", "474", "475", "476", "477", "478", "479", + "480", "481", "482", "483", "484", "485", "486", "487", "488", "489", + "490", "491", "492", "493", "494", "495", "496", "497", "498", "499", + + "500", "501", "502", "503", "504", "505", "506", "507", "508", "509", + "510", "511", "512", "513", "514", "515", "516", "517", "518", "519", + "520", "521", "522", "523", "524", "525", "526", "527", "528", "529", + "530", "531", "532", "533", "534", "535", "536", "537", "538", "539", + "540", "541", "542", "543", "544", "545", "546", "547", "548", "549", + "550", "551", "552", "553", "554", "555", "556", "557", "558", "559", + "560", "561", "562", "563", "564", "565", "566", "567", "568", "569", + "570", "571", "572", "573", "574", "575", "576", "577", "578", "579", + "580", "581", "582", "583", "584", "585", "586", "587", "588", "589", + "590", "591", "592", "593", "594", "595", "596", "597", "598", "599", + + "600", "601", "602", "603", "604", "605", "606", "607", "608", "609", + "610", "611", "612", "613", "614", "615", "616", "617", "618", "619", + "620", "621", "622", "623", "624", "625", "626", "627", "628", "629", + "630", "631", "632", "633", "634", "635", "636", "637", "638", "639", + "640", "641", "642", "643", "644", "645", "646", "647", "648", "649", + "650", "651", "652", "653", "654", "655", "656", "657", "658", "659", + "660", "661", "662", "663", "664", "665", "666", "667", "668", "669", + "670", "671", "672", "673", "674", "675", "676", "677", "678", "679", + "680", "681", "682", "683", "684", "685", "686", "687", "688", "689", + "690", "691", "692", "693", "694", "695", "696", "697", "698", "699", + + "700", "701", "702", "703", "704", "705", "706", "707", "708", "709", + "710", "711", "712", "713", "714", "715", "716", "717", "718", "719", + "720", "721", "722", "723", "724", "725", "726", "727", "728", "729", + "730", "731", "732", "733", "734", "735", "736", "737", "738", "739", + "740", "741", "742", "743", "744", "745", "746", "747", "748", "749", + "750", "751", "752", "753", "754", "755", "756", "757", "758", "759", + "760", "761", "762", "763", "764", "765", "766", "767", "768", "769", + "770", "771", "772", "773", "774", "775", "776", "777", "778", "779", + "780", "781", "782", "783", "784", "785", "786", "787", "788", "789", + "790", "791", "792", "793", "794", "795", "796", "797", "798", "799", + + "800", "801", "802", "803", "804", "805", "806", "807", "808", "809", + "810", "811", "812", "813", "814", "815", "816", "817", "818", "819", + "820", "821", "822", "823", "824", "825", "826", "827", "828", "829", + "830", "831", "832", "833", "834", "835", "836", "837", "838", "839", + "840", "841", "842", "843", "844", "845", "846", "847", "848", "849", + "850", "851", "852", "853", "854", "855", "856", "857", "858", "859", + "860", "861", "862", "863", "864", "865", "866", "867", "868", "869", + "870", "871", "872", "873", "874", "875", "876", "877", "878", "879", + "880", "881", "882", "883", "884", "885", "886", "887", "888", "889", + "890", "891", "892", "893", "894", "895", "896", "897", "898", "899", + + "900", "901", "902", "903", "904", "905", "906", "907", "908", "909", + "910", "911", "912", "913", "914", "915", "916", "917", "918", "919", + "920", "921", "922", "923", "924", "925", "926", "927", "928", "929", + "930", "931", "932", "933", "934", "935", "936", "937", "938", "939", + "940", "941", "942", "943", "944", "945", "946", "947", "948", "949", + "950", "951", "952", "953", "954", "955", "956", "957", "958", "959", + "960", "961", "962", "963", "964", "965", "966", "967", "968", "969", + "970", "971", "972", "973", "974", "975", "976", "977", "978", "979", + "980", "981", "982", "983", "984", "985", "986", "987", "988", "989", + "990", "991", "992", "993", "994", "995", "996", "997", "998", "999", +}; + +enum bson_error_t { + BSON_SIZE_OVERFLOW = 1 /**< Trying to create a BSON object larger than INT_MAX. */ +}; + +enum bson_validity_t { + BSON_VALID = 0, /**< BSON is valid and UTF-8 compliant. */ + BSON_NOT_UTF8 = ( 1<<1 ), /**< A key or a string is not valid UTF-8. */ + BSON_FIELD_HAS_DOT = ( 1<<2 ), /**< Warning: key contains '.' character. */ + BSON_FIELD_INIT_DOLLAR = ( 1<<3 ), /**< Warning: key starts with '$' character. */ + BSON_ALREADY_FINISHED = ( 1<<4 ) /**< Trying to modify a finished BSON object. */ +}; + +enum bson_binary_subtype_t { + BSON_BIN_BINARY = 0, + BSON_BIN_FUNC = 1, + BSON_BIN_BINARY_OLD = 2, + BSON_BIN_UUID = 3, + BSON_BIN_MD5 = 5, + BSON_BIN_USER = 128 +}; + +typedef enum { + BSON_EOO = 0, + BSON_DOUBLE = 1, + BSON_STRING = 2, + BSON_OBJECT = 3, + BSON_ARRAY = 4, + BSON_BINDATA = 5, + BSON_UNDEFINED = 6, + BSON_OID = 7, + BSON_BOOL = 8, + BSON_DATE = 9, + BSON_NULL = 10, + BSON_REGEX = 11, + BSON_DBREF = 12, /**< Deprecated. */ + BSON_CODE = 13, + BSON_SYMBOL = 14, + BSON_CODEWSCOPE = 15, + BSON_INT = 16, + BSON_TIMESTAMP = 17, + BSON_LONG = 18 +} bson_type; + +typedef int bson_bool_t; + +typedef struct { + const char *cur; + bson_bool_t first; +} bson_iterator; + +typedef struct { + char *data; + char *cur; + int dataSize; + bson_bool_t finished; + int stack[32]; + int stackPos; + int err; /**< Bitfield representing errors or warnings on this buffer */ + char *errstr; /**< A string representation of the most recent error or warning. */ +} bson; + +#pragma pack(1) +typedef union { + char bytes[12]; + int ints[3]; +} bson_oid_t; +#pragma pack() + +typedef int64_t bson_date_t; /* milliseconds since epoch UTC */ + +typedef struct { + int i; /* increment */ + int t; /* time in seconds */ +} bson_timestamp_t; + +/* ---------------------------- + READING + ------------------------------ */ + +/** + * Size of a BSON object. + * + * @param b the BSON object. + * + * @return the size. + */ +int bson_size( const bson *b ); + +/** + * Print a string representation of a BSON object. + * + * @param b the BSON object to print. + */ +void bson_print( bson *b ); + +/** + * Return a pointer to the raw buffer stored by this bson object. + * + * @param b a BSON object + */ +const char *bson_data( bson *b ); + +/** + * Print a string representation of a BSON object. + * + * @param bson the raw data to print. + * @param depth the depth to recurse the object.x + */ +void bson_print_raw( const char *bson , int depth ); + +/** + * Advance a bson_iterator to the named field. + * + * @param it the bson_iterator to use. + * @param obj the BSON object to use. + * @param name the name of the field to find. + * + * @return the type of the found object or BSON_EOO if it is not found. + */ +bson_type bson_find( bson_iterator *it, const bson *obj, const char *name ); + +/** + * Initialize a bson_iterator. + * + * @param i the bson_iterator to initialize. + * @param bson the BSON object to associate with the iterator. + */ +void bson_iterator_init( bson_iterator *i , const bson *b ); + +/** + * Initialize a bson iterator from a const char* buffer. Note + * that this is mostly used internally. + * + * @param i the bson_iterator to initialize. + * @param buffer the buffer to point to. + */ +void bson_iterator_from_buffer( bson_iterator *i, const char *buffer ); + +/* more returns true for eoo. best to loop with bson_iterator_next(&it) */ +/** + * Check to see if the bson_iterator has more data. + * + * @param i the iterator. + * + * @return returns true if there is more data. + */ +bson_bool_t bson_iterator_more( const bson_iterator *i ); + +/** + * Point the iterator at the next BSON object. + * + * @param i the bson_iterator. + * + * @return the type of the next BSON object. + */ +bson_type bson_iterator_next( bson_iterator *i ); + +/** + * Get the type of the BSON object currently pointed to by the iterator. + * + * @param i the bson_iterator + * + * @return the type of the current BSON object. + */ +bson_type bson_iterator_type( const bson_iterator *i ); + +/** + * Get the key of the BSON object currently pointed to by the iterator. + * + * @param i the bson_iterator + * + * @return the key of the current BSON object. + */ +const char *bson_iterator_key( const bson_iterator *i ); + +/** + * Get the value of the BSON object currently pointed to by the iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +const char *bson_iterator_value( const bson_iterator *i ); + +/* these convert to the right type (return 0 if non-numeric) */ +/** + * Get the double value of the BSON object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +double bson_iterator_double( const bson_iterator *i ); + +/** + * Get the int value of the BSON object currently pointed to by the iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +int bson_iterator_int( const bson_iterator *i ); + +/** + * Get the long value of the BSON object currently pointed to by the iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +int64_t bson_iterator_long( const bson_iterator *i ); + +/* return the bson timestamp as a whole or in parts */ +/** + * Get the timestamp value of the BSON object currently pointed to by + * the iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +bson_timestamp_t bson_iterator_timestamp( const bson_iterator *i ); + +/** + * Get the boolean value of the BSON object currently pointed to by + * the iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +/* false: boolean false, 0 in any type, or null */ +/* true: anything else (even empty strings and objects) */ +bson_bool_t bson_iterator_bool( const bson_iterator *i ); + +/** + * Get the double value of the BSON object currently pointed to by the + * iterator. Assumes the correct type is used. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +/* these assume you are using the right type */ +double bson_iterator_double_raw( const bson_iterator *i ); + +/** + * Get the int value of the BSON object currently pointed to by the + * iterator. Assumes the correct type is used. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +int bson_iterator_int_raw( const bson_iterator *i ); + +/** + * Get the long value of the BSON object currently pointed to by the + * iterator. Assumes the correct type is used. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +int64_t bson_iterator_long_raw( const bson_iterator *i ); + +/** + * Get the bson_bool_t value of the BSON object currently pointed to by the + * iterator. Assumes the correct type is used. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +bson_bool_t bson_iterator_bool_raw( const bson_iterator *i ); + +/** + * Get the bson_oid_t value of the BSON object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +bson_oid_t *bson_iterator_oid( const bson_iterator *i ); + +/** + * Get the string value of the BSON object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +/* these can also be used with bson_code and bson_symbol*/ +const char *bson_iterator_string( const bson_iterator *i ); + +/** + * Get the string length of the BSON object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the length of the current BSON object. + */ +int bson_iterator_string_len( const bson_iterator *i ); + +/** + * Get the code value of the BSON object currently pointed to by the + * iterator. Works with bson_code, bson_codewscope, and BSON_STRING + * returns NULL for everything else. + * + * @param i the bson_iterator + * + * @return the code value of the current BSON object. + */ +/* works with bson_code, bson_codewscope, and BSON_STRING */ +/* returns NULL for everything else */ +const char *bson_iterator_code( const bson_iterator *i ); + +/** + * Calls bson_empty on scope if not a bson_codewscope + * + * @param i the bson_iterator. + * @param scope the bson scope. + */ +/* calls bson_empty on scope if not a bson_codewscope */ +void bson_iterator_code_scope( const bson_iterator *i, bson *scope ); + +/** + * Get the date value of the BSON object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the date value of the current BSON object. + */ +/* both of these only work with bson_date */ +bson_date_t bson_iterator_date( const bson_iterator *i ); + +/** + * Get the time value of the BSON object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the time value of the current BSON object. + */ +time_t bson_iterator_time_t( const bson_iterator *i ); + +/** + * Get the length of the BSON binary object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the length of the current BSON binary object. + */ +int bson_iterator_bin_len( const bson_iterator *i ); + +/** + * Get the type of the BSON binary object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the type of the current BSON binary object. + */ +char bson_iterator_bin_type( const bson_iterator *i ); + +/** + * Get the value of the BSON binary object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON binary object. + */ +const char *bson_iterator_bin_data( const bson_iterator *i ); + +/** + * Get the value of the BSON regex object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON regex object. + */ +const char *bson_iterator_regex( const bson_iterator *i ); + +/** + * Get the options of the BSON regex object currently pointed to by the + * iterator. + * + * @param i the bson_iterator. + * + * @return the options of the current BSON regex object. + */ +const char *bson_iterator_regex_opts( const bson_iterator *i ); + +/* these work with BSON_OBJECT and BSON_ARRAY */ +/** + * Get the BSON subobject currently pointed to by the + * iterator. + * + * @param i the bson_iterator. + * @param sub the BSON subobject destination. + */ +void bson_iterator_subobject( const bson_iterator *i, bson *sub ); + +/** + * Get a bson_iterator that on the BSON subobject. + * + * @param i the bson_iterator. + * @param sub the iterator to point at the BSON subobject. + */ +void bson_iterator_subiterator( const bson_iterator *i, bson_iterator *sub ); + +/* str must be at least 24 hex chars + null byte */ +/** + * Create a bson_oid_t from a string. + * + * @param oid the bson_oid_t destination. + * @param str a null terminated string comprised of at least 24 hex chars. + */ +void bson_oid_from_string( bson_oid_t *oid, const char *str ); + +/** + * Create a string representation of the bson_oid_t. + * + * @param oid the bson_oid_t source. + * @param str the string representation destination. + */ +void bson_oid_to_string( const bson_oid_t *oid, char *str ); + +/** + * Create a bson_oid object. + * + * @param oid the destination for the newly created bson_oid_t. + */ +void bson_oid_gen( bson_oid_t *oid ); + +/** + * Set a function to be used to generate the second four bytes + * of an object id. + * + * @param func a pointer to a function that returns an int. + */ +void bson_set_oid_fuzz( int ( *func )( void ) ); + +/** + * Set a function to be used to generate the incrementing part + * of an object id (last four bytes). If you need thread-safety + * in generating object ids, you should set this function. + * + * @param func a pointer to a function that returns an int. + */ +void bson_set_oid_inc( int ( *func )( void ) ); + +/** + * Get the time a bson_oid_t was created. + * + * @param oid the bson_oid_t. + */ +time_t bson_oid_generated_time( bson_oid_t *oid ); /* Gives the time the OID was created */ + +/* ---------------------------- + BUILDING + ------------------------------ */ + +/** + * Initialize a new bson object. If not created + * with bson_new, you must initialize each new bson + * object using this function. + * + * @note When finished, you must pass the bson object to + * bson_destroy( ). + */ +void bson_init( bson *b ); + +/** + * Initialize a BSON object, and point its data + * pointer to the provided char*. + * + * @param b the BSON object to initialize. + * @param data the raw BSON data. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_init_data( bson *b , char *data ); + +/** + * Initialize a BSON object, and point its data + * pointer to the provided char*. We assume + * that the data represents a finished BSON object. + * + * @param b the BSON object to initialize. + * @param data the raw BSON data. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_init_finished_data( bson *b, char *data ); + +/** + * Initialize a BSON object, and set its + * buffer to the given size. + * + * @param b the BSON object to initialize. + * @param size the initial size of the buffer. + * + * @return BSON_OK or BSON_ERROR. + */ +void bson_init_size( bson *b, int size ); + +/** + * Grow a bson object. + * + * @param b the bson to grow. + * @param bytesNeeded the additional number of bytes needed. + * + * @return BSON_OK or BSON_ERROR with the bson error object set. + * Exits if allocation fails. + */ +int bson_ensure_space( bson *b, const int bytesNeeded ); + +/** + * Finalize a bson object. + * + * @param b the bson object to finalize. + * + * @return the standard error code. To deallocate memory, + * call bson_destroy on the bson object. + */ +int bson_finish( bson *b ); + +/** + * Destroy a bson object. + * + * @param b the bson object to destroy. + * + */ +void bson_destroy( bson *b ); + +/** + * Returns a pointer to a static empty BSON object. + * + * @param obj the BSON object to initialize. + * + * @return the empty initialized BSON object. + */ +/* returns pointer to static empty bson object */ +bson *bson_empty( bson *obj ); + +/** + * Make a complete copy of the a BSON object. + * The source bson object must be in a finished + * state; otherwise, the copy will fail. + * + * @param out the copy destination BSON object. + * @param in the copy source BSON object. + */ +int bson_copy( bson *out, const bson *in ); /* puts data in new buffer. NOOP if out==NULL */ + +/** + * Append a previously created bson_oid_t to a bson object. + * + * @param b the bson to append to. + * @param name the key for the bson_oid_t. + * @param oid the bson_oid_t to append. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_oid( bson *b, const char *name, const bson_oid_t *oid ); + +/** + * Append a bson_oid_t to a bson. + * + * @param b the bson to append to. + * @param name the key for the bson_oid_t. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_new_oid( bson *b, const char *name ); + +/** + * Append an int to a bson. + * + * @param b the bson to append to. + * @param name the key for the int. + * @param i the int to append. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_int( bson *b, const char *name, const int i ); + +/** + * Append an long to a bson. + * + * @param b the bson to append to. + * @param name the key for the long. + * @param i the long to append. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_long( bson *b, const char *name, const int64_t i ); + +/** + * Append an double to a bson. + * + * @param b the bson to append to. + * @param name the key for the double. + * @param d the double to append. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_double( bson *b, const char *name, const double d ); + +/** + * Append a string to a bson. + * + * @param b the bson to append to. + * @param name the key for the string. + * @param str the string to append. + * + * @return BSON_OK or BSON_ERROR. +*/ +int bson_append_string( bson *b, const char *name, const char *str ); + +/** + * Append len bytes of a string to a bson. + * + * @param b the bson to append to. + * @param name the key for the string. + * @param str the string to append. + * @param len the number of bytes from str to append. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_string_n( bson *b, const char *name, const char *str, int len ); + +/** + * Append a symbol to a bson. + * + * @param b the bson to append to. + * @param name the key for the symbol. + * @param str the symbol to append. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_symbol( bson *b, const char *name, const char *str ); + +/** + * Append len bytes of a symbol to a bson. + * + * @param b the bson to append to. + * @param name the key for the symbol. + * @param str the symbol to append. + * @param len the number of bytes from str to append. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_symbol_n( bson *b, const char *name, const char *str, int len ); + +/** + * Append code to a bson. + * + * @param b the bson to append to. + * @param name the key for the code. + * @param str the code to append. + * @param len the number of bytes from str to append. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_code( bson *b, const char *name, const char *str ); + +/** + * Append len bytes of code to a bson. + * + * @param b the bson to append to. + * @param name the key for the code. + * @param str the code to append. + * @param len the number of bytes from str to append. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_code_n( bson *b, const char *name, const char *str, int len ); + +/** + * Append code to a bson with scope. + * + * @param b the bson to append to. + * @param name the key for the code. + * @param str the string to append. + * @param scope a BSON object containing the scope. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_code_w_scope( bson *b, const char *name, const char *code, const bson *scope ); + +/** + * Append len bytes of code to a bson with scope. + * + * @param b the bson to append to. + * @param name the key for the code. + * @param str the string to append. + * @param len the number of bytes from str to append. + * @param scope a BSON object containing the scope. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_code_w_scope_n( bson *b, const char *name, const char *code, int size, const bson *scope ); + +/** + * Append binary data to a bson. + * + * @param b the bson to append to. + * @param name the key for the data. + * @param type the binary data type. + * @param str the binary data. + * @param len the length of the data. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_binary( bson *b, const char *name, char type, const char *str, int len ); + +/** + * Append a bson_bool_t to a bson. + * + * @param b the bson to append to. + * @param name the key for the boolean value. + * @param v the bson_bool_t to append. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_bool( bson *b, const char *name, const bson_bool_t v ); + +/** + * Append a null value to a bson. + * + * @param b the bson to append to. + * @param name the key for the null value. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_null( bson *b, const char *name ); + +/** + * Append an undefined value to a bson. + * + * @param b the bson to append to. + * @param name the key for the undefined value. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_undefined( bson *b, const char *name ); + +/** + * Append a regex value to a bson. + * + * @param b the bson to append to. + * @param name the key for the regex value. + * @param pattern the regex pattern to append. + * @param the regex options. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_regex( bson *b, const char *name, const char *pattern, const char *opts ); + +/** + * Append bson data to a bson. + * + * @param b the bson to append to. + * @param name the key for the bson data. + * @param bson the bson object to append. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_bson( bson *b, const char *name, const bson *bson ); + +/** + * Append a BSON element to a bson from the current point of an iterator. + * + * @param b the bson to append to. + * @param name_or_null the key for the BSON element, or NULL. + * @param elem the bson_iterator. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_element( bson *b, const char *name_or_null, const bson_iterator *elem ); + +/** + * Append a bson_timestamp_t value to a bson. + * + * @param b the bson to append to. + * @param name the key for the timestampe value. + * @param ts the bson_timestamp_t value to append. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_timestamp( bson *b, const char *name, bson_timestamp_t *ts ); + +/* these both append a bson_date */ +/** + * Append a bson_date_t value to a bson. + * + * @param b the bson to append to. + * @param name the key for the date value. + * @param millis the bson_date_t to append. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_date( bson *b, const char *name, bson_date_t millis ); + +/** + * Append a time_t value to a bson. + * + * @param b the bson to append to. + * @param name the key for the date value. + * @param secs the time_t to append. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_time_t( bson *b, const char *name, time_t secs ); + +/** + * Start appending a new object to a bson. + * + * @param b the bson to append to. + * @param name the name of the new object. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_start_object( bson *b, const char *name ); + +/** + * Start appending a new array to a bson. + * + * @param b the bson to append to. + * @param name the name of the new array. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_start_array( bson *b, const char *name ); + +/** + * Finish appending a new object or array to a bson. + * + * @param b the bson to append to. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_finish_object( bson *b ); + +/** + * Finish appending a new object or array to a bson. This + * is simply an alias for bson_append_finish_object. + * + * @param b the bson to append to. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_append_finish_array( bson *b ); + +void bson_numstr( char *str, int i ); + +void bson_incnumstr( char *str ); + +/* Error handling and stadard library function over-riding. */ +/* -------------------------------------------------------- */ + +/* bson_err_handlers shouldn't return!!! */ +typedef void( *bson_err_handler )( const char *errmsg ); + +typedef int (*bson_printf_func)( const char *, ... ); +typedef int (*bson_fprintf_func)( FILE *, const char *, ... ); +typedef int (*bson_sprintf_func)( char *, const char *, ... ); + +extern void *( *bson_malloc_func )( size_t ); +extern void *( *bson_realloc_func )( void *, size_t ); +extern void ( *bson_free )( void * ); + +extern bson_printf_func bson_printf; +extern bson_fprintf_func bson_fprintf; +extern bson_sprintf_func bson_sprintf; + +extern bson_printf_func bson_errprintf; + +/** + * Allocates memory and checks return value, exiting fatally if malloc() fails. + * + * @param size bytes to allocate. + * + * @return a pointer to the allocated memory. + * + * @sa malloc(3) + */ +void *bson_malloc( int size ); + +/** + * Changes the size of allocated memory and checks return value, + * exiting fatally if realloc() fails. + * + * @param ptr pointer to the space to reallocate. + * @param size bytes to allocate. + * + * @return a pointer to the allocated memory. + * + * @sa realloc() + */ +void *bson_realloc( void *ptr, int size ); + +/** + * Set a function for error handling. + * + * @param func a bson_err_handler function. + * + * @return the old error handling function, or NULL. + */ +bson_err_handler set_bson_err_handler( bson_err_handler func ); + +/* does nothing if ok != 0 */ +/** + * Exit fatally. + * + * @param ok exits if ok is equal to 0. + */ +void bson_fatal( int ok ); + +/** + * Exit fatally with an error message. + * + * @param ok exits if ok is equal to 0. + * @param msg prints to stderr before exiting. + */ +void bson_fatal_msg( int ok, const char *msg ); + +/** + * Invoke the error handler, but do not exit. + * + * @param b the buffer object. + */ +void bson_builder_error( bson *b ); + +/* encoding.h */ + +/* + * 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. + */ + +/** + * Check that a field name is valid UTF8, does not start with a '$', + * and contains no '.' characters. Set bson bit field appropriately. + * Note that we don't need to check for '\0' because we're using + * strlen(3), which stops at '\0'. + * + * @param b The bson object to which field name will be appended. + * @param string The field name as char*. + * @param length The length of the field name. + * + * @return BSON_OK if valid UTF8 and BSON_ERROR if not. All BSON strings must be + * valid UTF8. This function will also check whether the string + * contains '.' or starts with '$', since the validity of this depends on context. + * Set the value of b->err appropriately. + */ +int bson_check_field_name( bson *b, const char *string, + const int length ); + +/** + * Check that a string is valid UTF8. Sets the buffer bit field appropriately. + * + * @param b The bson object to which string will be appended. + * @param string The string to check. + * @param length The length of the string. + * + * @return BSON_OK if valid UTF-8; otherwise, BSON_ERROR. + * Sets b->err on error. + */ +bson_bool_t bson_check_string( bson *b, const char *string, + const int length ); + +/* platform.h */ + +/** 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. + */ + + +/* all platform-specific ifdefs should go here */ + +/* big endian is only used for OID generation. little is used everywhere else */ +//#ifdef BIG_ENDIAN +//#define bson_little_endian64(out, in) ( bson_swap_endian64(out, in) ) +//#define bson_little_endian32(out, in) ( bson_swap_endian32(out, in) ) +//#define bson_big_endian64(out, in) ( memcpy(out, in, 8) ) +//#define bson_big_endian32(out, in) ( memcpy(out, in, 4) ) +//#else +#define bson_little_endian64(out, in) ( memcpy(out, in, 8) ) +#define bson_little_endian32(out, in) ( memcpy(out, in, 4) ) +#define bson_big_endian64(out, in) ( bson_swap_endian64(out, in) ) +#define bson_big_endian32(out, in) ( bson_swap_endian32(out, in) ) +//#endif + +static TPT_INLINE void bson_swap_endian64( void *outp, const void *inp ) { + const char *in = ( const char * )inp; + char *out = ( char * )outp; + + out[0] = in[7]; + out[1] = in[6]; + out[2] = in[5]; + out[3] = in[4]; + out[4] = in[3]; + out[5] = in[2]; + out[6] = in[1]; + out[7] = in[0]; + +} +static TPT_INLINE void bson_swap_endian32( void *outp, const void *inp ) { + const char *in = ( const char * )inp; + char *out = ( char * )outp; + + out[0] = in[3]; + out[1] = in[2]; + out[2] = in[1]; + out[3] = in[0]; +} + +#endif \ No newline at end of file diff --git a/includes/defines.h b/includes/defines.h index b33c0f05e..f81e6a4e6 100644 --- a/includes/defines.h +++ b/includes/defines.h @@ -123,6 +123,12 @@ typedef unsigned int pixel; #define fmaxf max #endif +#if defined(WIN32) && !defined(__GNUC__) +#define TPT_INLINE _inline +#else +#define TPT_INLINE inline +#endif + #define SDEUT //#define REALHEAT @@ -242,9 +248,6 @@ extern char http_proxy_string[256]; void thumb_cache_inval(char *id); void thumb_cache_add(char *id, void *thumb, int size); int thumb_cache_find(char *id, void **thumb, int *size); -void *build_thumb(int *size, int bzip2); -void *build_save(int *size, int x0, int y0, int w, int 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); -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]); void clear_sim(void); void del_stamp(int d); void sdl_seticon(void); diff --git a/includes/save.h b/includes/save.h new file mode 100644 index 000000000..3b4cc7cf2 --- /dev/null +++ b/includes/save.h @@ -0,0 +1,19 @@ +#ifndef SAVE_H +#define SAVE_H + +void *build_thumb(int *size, int bzip2); + +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); + +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]); + +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* partsptr); + +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* partsptr, unsigned pmap[YRES][XRES]); + +//Old save parsers, readers +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); + +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]); + +#endif \ No newline at end of file diff --git a/src/BSON.c b/src/BSON.c new file mode 100644 index 000000000..62dfc4fc8 --- /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 +#include +#include +#include +#include + +#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 472fd9b29..bb34c15f1 100644 --- a/src/interface.c +++ b/src/interface.c @@ -26,6 +26,7 @@ #include #endif #include +#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; diff --git a/src/main.c b/src/main.c index fd4f34e71..a835e3e72 100644 --- a/src/main.c +++ b/src/main.c @@ -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=0 && x=0 && y255) i=255; - d[p++] = i; - } - for (y=by0; y255) i=255; - d[p++] = i; - } - - // save the particle map - for (i=0; i=orig_x0 && x=orig_y0 && y255) x=255; - if (y<0) y=0; - if (y>255) y=255; - d[p++] = x; - d[p++] = y; - } - } - for (j=0; j>8); - d[p++] = (ttlife&0x00FF); - } - } - for (j=0; j>8); - d[p++] = (tttmp&0x00FF); - } - } - for (j=0; j>24; - } - } - for (j=0; j>16; - } - } - for (j=0; j>8; - } - } - for (j=0; j>8); - d[p++] = (tttemp&0x00FF); - } - } - for (j=0; j=x0 && signs[i].x=y0 && signs[i].y=x0 && signs[i].x=y0 && signs[i].y>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= size) - goto corrupt; - fvx[y][x] = (d[p++]-127.0f)/64.0f; - } - for (y=by0; y= size) - goto corrupt; - fvy[y][x] = (d[p++]-127.0f)/64.0f; - } - - // load the particle map - i = 0; - pty = p; - for (y=y0; y= 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= 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=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= 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= size) - goto corrupt; - if (i <= NPART) - parts[i-1].tmp2 = d[p++]; - else - p++; - } - } - } - //Read ALPHA component - for (j=0; j=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=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=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=49) { - if (p >= size) { - goto corrupt; - } - if (i <= NPART) { - parts[i-1].dcolour |= d[p++]; - } else { - p++; - } - } - } - } - for (j=0; j=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=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=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 size) - goto corrupt; - for (k=0; k size) - goto corrupt; - if (k=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 000000000..68829797e --- /dev/null +++ b/src/save.c @@ -0,0 +1,1266 @@ +#include +#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= 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; y255) i=255; + d[p++] = i; + } + for (y=by0; y255) i=255; + d[p++] = i; + } + + // save the particle map + for (i=0; i=orig_x0 && x=orig_y0 && y255) x=255; + if (y<0) y=0; + if (y>255) y=255; + d[p++] = x; + d[p++] = y; + } + } + for (j=0; j>8); + d[p++] = (ttlife&0x00FF); + } + } + for (j=0; j>8); + d[p++] = (tttmp&0x00FF); + } + } + for (j=0; j>24; + } + } + for (j=0; j>16; + } + } + for (j=0; j>8; + } + } + for (j=0; j>8); + d[p++] = (tttemp&0x00FF); + } + } + for (j=0; j=x0 && signs[i].x=y0 && signs[i].y=x0 && signs[i].x=y0 && signs[i].y>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= size) + goto corrupt; + fvx[y][x] = (d[p++]-127.0f)/64.0f; + } + for (y=by0; y= size) + goto corrupt; + fvy[y][x] = (d[p++]-127.0f)/64.0f; + } + + // load the particle map + i = 0; + pty = p; + for (y=y0; y= 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= 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=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= 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= size) + goto corrupt; + if (i <= NPART) + parts[i-1].tmp2 = d[p++]; + else + p++; + } + } + } + //Read ALPHA component + for (j=0; j=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=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=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=49) { + if (p >= size) { + goto corrupt; + } + if (i <= NPART) { + parts[i-1].dcolour |= d[p++]; + } else { + p++; + } + } + } + } + for (j=0; j=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=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=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 size) + goto corrupt; + for (k=0; k size) + goto corrupt; + if (k=0 && x=0 && y