static tb_object_ref_t tb_object_bin_reader_func_number(tb_object_bin_reader_t* reader, tb_size_t type, tb_uint64_t size) { // check tb_assert_and_check_return_val(reader && reader->stream && reader->list, tb_null); // the number type tb_size_t number_type = (tb_size_t)size; // read number tb_object_ref_t number = tb_null; switch (number_type) { case TB_NUMBER_TYPE_UINT64: number = tb_object_number_init_from_uint64(tb_stream_bread_u64_be(reader->stream)); break; case TB_NUMBER_TYPE_SINT64: number = tb_object_number_init_from_sint64(tb_stream_bread_s64_be(reader->stream)); break; case TB_NUMBER_TYPE_UINT32: number = tb_object_number_init_from_uint32(tb_stream_bread_u32_be(reader->stream)); break; case TB_NUMBER_TYPE_SINT32: number = tb_object_number_init_from_sint32(tb_stream_bread_s32_be(reader->stream)); break; case TB_NUMBER_TYPE_UINT16: number = tb_object_number_init_from_uint16(tb_stream_bread_u16_be(reader->stream)); break; case TB_NUMBER_TYPE_SINT16: number = tb_object_number_init_from_sint16(tb_stream_bread_s16_be(reader->stream)); break; case TB_NUMBER_TYPE_UINT8: number = tb_object_number_init_from_uint8(tb_stream_bread_u8(reader->stream)); break; case TB_NUMBER_TYPE_SINT8: number = tb_object_number_init_from_sint8(tb_stream_bread_s8(reader->stream)); break; #ifdef TB_CONFIG_TYPE_FLOAT case TB_NUMBER_TYPE_FLOAT: { tb_byte_t data[4] = {0}; if (!tb_stream_bread(reader->stream, data, 4)) return tb_null; number = tb_object_number_init_from_float(tb_bits_get_float_be(data)); } break; case TB_NUMBER_TYPE_DOUBLE: { tb_byte_t data[8] = {0}; if (!tb_stream_bread(reader->stream, data, 8)) return tb_null; number = tb_object_number_init_from_double(tb_bits_get_double_bbe(data)); } break; #endif default: tb_assert_and_check_return_val(0, tb_null); break; } // ok? return number; }
/* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ tb_size_t tb_database_sqlite3_probe(tb_url_ref_t url) { // check tb_assert_and_check_return_val(url, 0); // done tb_size_t score = 0; tb_stream_ref_t stream = tb_null; do { // the url arguments tb_char_t const* args = tb_url_args(url); if (args) { // find the database type tb_char_t const* ptype = tb_stristr(args, "type="); if (ptype && !tb_strnicmp(ptype + 5, "sqlite3", 7)) { // ok score = 100; break; } } // has host or port? no sqlite3 if (tb_url_host(url) || tb_url_port(url)) break; // the database path tb_char_t const* path = tb_url_cstr((tb_url_ref_t)url); tb_assert_and_check_break(path); // is file? if (tb_url_protocol(url) == TB_URL_PROTOCOL_FILE) score += 20; // init stream stream = tb_stream_init_from_url(path); tb_assert_and_check_break(stream); // open stream if (!tb_stream_open(stream)) break; // read head tb_char_t head[16] = {0}; if (!tb_stream_bread(stream, (tb_byte_t*)head, 15)) break; // is sqlite3? if (!tb_stricmp(head, "SQLite format 3")) score = 100; } while (0); // exit stream if (stream) tb_stream_exit(stream); stream = tb_null; // trace tb_trace_d("probe: %s, score: %lu", tb_url_cstr((tb_url_ref_t)url), score); // ok? return score; }
static tb_object_ref_t tb_object_bin_reader_done(tb_stream_ref_t stream) { // read bin header tb_byte_t data[32] = {0}; if (!tb_stream_bread(stream, data, 5)) return tb_null; // check if (tb_strnicmp((tb_char_t const*)data, "tbo00", 5)) return tb_null; // init tb_object_ref_t object = tb_null; tb_object_bin_reader_t reader = {0}; // init reader reader.stream = stream; reader.list = tb_vector_init(256, tb_item_func_obj()); tb_assert_and_check_return_val(reader.list, tb_null); // the type & size tb_size_t type = 0; tb_uint64_t size = 0; tb_object_reader_bin_type_size(stream, &type, &size); // trace tb_trace_d("root: type: %lu, size: %llu", type, size); // the func tb_object_bin_reader_func_t func = tb_object_bin_reader_func(type); // check tb_assert(func); // read it if (func) object = func(&reader, type, size); // exit the list if (reader.list) tb_vector_exit(reader.list); // ok? return object; }
static tb_object_ref_t tb_object_bplist_reader_func_array(tb_object_bplist_reader_t* reader, tb_size_t type, tb_size_t size, tb_size_t item_size) { // check tb_assert_and_check_return_val(reader && reader->stream, tb_null); // init tb_object_ref_t object = tb_null; // size is too large? if (size == 0x0f) { // read size tb_long_t val = tb_object_bplist_reader_func_size(reader, item_size); tb_assert_and_check_return_val(val >= 0, tb_null); size = (tb_size_t)val; } // init array object = tb_object_array_init(size? size : 16, tb_false); tb_assert_and_check_return_val(object, tb_null); // init items data if (size) { tb_byte_t* data = tb_malloc_bytes(sizeof(tb_uint32_t) + (size * item_size)); if (data) { if (tb_stream_bread(reader->stream, data + sizeof(tb_uint32_t), size * item_size)) { tb_bits_set_u32_ne(data, (tb_uint32_t)size); // FIXME: not using the user private data tb_object_setp(object, data); } else tb_free(data); } } // ok? return object; }
static tb_object_ref_t tb_object_bplist_reader_func_dictionary(tb_object_bplist_reader_t* reader, tb_size_t type, tb_size_t size, tb_size_t item_size) { // check tb_assert_and_check_return_val(reader && reader->stream, tb_null); // init tb_object_ref_t object = tb_null; // size is too large? if (size == 0x0f) { // read size tb_long_t val = tb_object_bplist_reader_func_size(reader, item_size); tb_assert_and_check_return_val(val >= 0, tb_null); size = (tb_size_t)val; } // init dictionary object = tb_object_dictionary_init(TB_OBJECT_DICTIONARY_SIZE_MICRO, tb_false); tb_assert_and_check_return_val(object, tb_null); // init items data if (size) { item_size <<= 1; tb_byte_t* data = tb_malloc_bytes(sizeof(tb_uint32_t) + (size * item_size)); if (data) { if (tb_stream_bread(reader->stream, data + sizeof(tb_uint32_t), size * item_size)) { tb_bits_set_u32_ne(data, (tb_uint32_t)size); tb_object_setp(object, data); } else tb_free(data); } } // ok? return object; }
/* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ tb_object_ref_t tb_object_data_init_from_url(tb_char_t const* url) { // check tb_assert_and_check_return_val(url, tb_null); // init stream tb_stream_ref_t stream = tb_stream_init_from_url(url); tb_assert_and_check_return_val(stream, tb_null); // make stream tb_object_ref_t object = tb_null; if (tb_stream_open(stream)) { // size tb_hong_t size = tb_stream_size(stream); if (size > 0 && size < TB_MAXS32) { tb_byte_t* data = tb_malloc0_bytes((tb_size_t)size); if (data) { if (tb_stream_bread(stream, data, (tb_size_t)size)) object = tb_object_data_init_from_data(data, (tb_size_t)size); tb_free(data); } } else object = tb_object_data_init_from_data(tb_null, 0); // check, TODO: read stream if no size tb_assert(size >= 0 && size < TB_MAXS32); // exit stream tb_stream_exit(stream); } // ok? return object; }
static tb_object_ref_t tb_object_bplist_reader_func_data(tb_object_bplist_reader_t* reader, tb_size_t type, tb_size_t size, tb_size_t item_size) { // check tb_assert_and_check_return_val(reader && reader->stream, tb_null); // init tb_byte_t* data = tb_null; tb_object_ref_t object = tb_null; // size is too large? if (size == 0x0f) { // read size tb_long_t val = tb_object_bplist_reader_func_size(reader, item_size); tb_assert_and_check_return_val(val >= 0, tb_null); size = (tb_size_t)val; } // no empty? if (size) { // make data data = tb_malloc_bytes(size); tb_assert_and_check_return_val(data, tb_null); // read data if (tb_stream_bread(reader->stream, data, size)) object = tb_object_data_init_from_data(data, size); } else object = tb_object_data_init_from_data(tb_null, 0); // exit if (data) tb_free(data); // ok? return object; }
static tb_object_ref_t tb_object_bin_reader_func_data(tb_object_bin_reader_t* reader, tb_size_t type, tb_uint64_t size) { // check tb_assert_and_check_return_val(reader && reader->stream && reader->list, tb_null); // empty? if (!size) return tb_object_data_init_from_data(tb_null, 0); // make data tb_char_t* data = tb_malloc0_cstr((tb_size_t)size); tb_assert_and_check_return_val(data, tb_null); // read data if (!tb_stream_bread(reader->stream, (tb_byte_t*)data, (tb_size_t)size)) { tb_free(data); return tb_null; } // decode data { tb_byte_t* pb = (tb_byte_t*)data; tb_byte_t* pe = (tb_byte_t*)data + size; tb_byte_t xb = (tb_byte_t)(((size >> 8) & 0xff) | (size & 0xff)); for (; pb < pe; pb++, xb++) *pb ^= xb; } // make the data object tb_object_ref_t object = tb_object_data_init_from_data(data, (tb_size_t)size); // exit data tb_free(data); // ok? return object; }
static tb_bool_t tb_database_sqlite3_statement_bind(tb_database_sql_impl_t* database, tb_database_sql_statement_ref_t statement, tb_database_sql_value_t const* list, tb_size_t size) { // check tb_database_sqlite3_t* sqlite = tb_database_sqlite3_cast(database); tb_assert_and_check_return_val(sqlite && sqlite->database && statement && list && size, tb_false); // the param count tb_size_t param_count = (tb_size_t)sqlite3_bind_parameter_count((sqlite3_stmt*)statement); tb_assert_and_check_return_val(size == param_count, tb_false); // walk tb_size_t i = 0; for (i = 0; i < size; i++) { // the value tb_database_sql_value_t const* value = &list[i]; // done tb_int_t ok = SQLITE_ERROR; tb_byte_t* data = tb_null; switch (value->type) { case TB_DATABASE_SQL_VALUE_TYPE_TEXT: tb_trace_i("sqlite3: test %lu %s", i, value->u.text.data); ok = sqlite3_bind_text((sqlite3_stmt*)statement, (tb_int_t)(i + 1), value->u.text.data, (tb_int_t)tb_database_sql_value_size(value), tb_null); break; case TB_DATABASE_SQL_VALUE_TYPE_INT64: case TB_DATABASE_SQL_VALUE_TYPE_UINT64: ok = sqlite3_bind_int64((sqlite3_stmt*)statement, (tb_int_t)(i + 1), tb_database_sql_value_int64(value)); break; case TB_DATABASE_SQL_VALUE_TYPE_INT32: case TB_DATABASE_SQL_VALUE_TYPE_INT16: case TB_DATABASE_SQL_VALUE_TYPE_INT8: case TB_DATABASE_SQL_VALUE_TYPE_UINT32: case TB_DATABASE_SQL_VALUE_TYPE_UINT16: case TB_DATABASE_SQL_VALUE_TYPE_UINT8: ok = sqlite3_bind_int((sqlite3_stmt*)statement, (tb_int_t)(i + 1), (tb_int_t)tb_database_sql_value_int32(value)); break; case TB_DATABASE_SQL_VALUE_TYPE_BLOB16: case TB_DATABASE_SQL_VALUE_TYPE_BLOB8: ok = sqlite3_bind_blob((sqlite3_stmt*)statement, (tb_int_t)(i + 1), value->u.blob.data, (tb_int_t)value->u.blob.size, tb_null); break; case TB_DATABASE_SQL_VALUE_TYPE_BLOB32: { if (value->u.blob.stream) { // done do { // the stream size tb_hong_t size = tb_stream_size(value->u.blob.stream); tb_assert_and_check_break(size >= 0); // make data data = tb_malloc0_bytes((tb_size_t)size); tb_assert_and_check_break(data); // read data if (!tb_stream_bread(value->u.blob.stream, data, (tb_size_t)size)) break; // bind it ok = sqlite3_bind_blob((sqlite3_stmt*)statement, (tb_int_t)(i + 1), data, (tb_int_t)size, tb_database_sqlite3_statement_bind_exit); } while (0); } else ok = sqlite3_bind_blob((sqlite3_stmt*)statement, (tb_int_t)(i + 1), value->u.blob.data, (tb_int_t)value->u.blob.size, tb_null); } break; #ifdef TB_CONFIG_TYPE_HAVE_FLOAT case TB_DATABASE_SQL_VALUE_TYPE_FLOAT: case TB_DATABASE_SQL_VALUE_TYPE_DOUBLE: ok = sqlite3_bind_double((sqlite3_stmt*)statement, (tb_int_t)(i + 1), (tb_double_t)tb_database_sql_value_double(value)); break; #endif case TB_DATABASE_SQL_VALUE_TYPE_NULL: ok = sqlite3_bind_null((sqlite3_stmt*)statement, (tb_int_t)(i + 1)); break; default: tb_trace_e("statement: bind: unknown value type: %lu", value->type); break; } // failed? if (SQLITE_OK != ok) { // exit data if (data) tb_free(data); data = tb_null; // save state sqlite->base.state = tb_database_sqlite3_state_from_errno(sqlite3_errcode(sqlite->database)); // trace tb_trace_e("statement: bind value[%lu] failed, error[%d]: %s", i, sqlite3_errcode(sqlite->database), sqlite3_errmsg(sqlite->database)); break; } } // ok? return (i == size)? tb_true : tb_false; }
static tb_object_ref_t tb_object_bplist_reader_done(tb_stream_ref_t stream) { // check tb_assert_and_check_return_val(stream, tb_null); // init root tb_object_ref_t root = tb_null; // init reader tb_object_bplist_reader_t reader = {0}; reader.stream = stream; // init size tb_hize_t size = tb_stream_size(stream); tb_assert_and_check_return_val(size, tb_null); // init data tb_byte_t data[32] = {0}; // read magic & version if (!tb_stream_bread(stream, data, 8)) return tb_null; // check magic & version if (tb_strncmp((tb_char_t const*)data, "bplist00", 8)) return tb_null; // seek to tail if (!tb_stream_seek(stream, size - 26)) return tb_null; // read offset size tb_size_t offset_size = tb_stream_bread_u8(stream); tb_trace_d("offset_size: %lu", offset_size); // read item size for array and dictionary tb_size_t item_size = tb_stream_bread_u8(stream); tb_trace_d("item_size: %lu", item_size); // read object count tb_size_t object_count = (tb_size_t)tb_stream_bread_u64_be(stream); tb_trace_d("object_count: %lu", object_count); // read root object tb_size_t root_object = (tb_size_t)tb_stream_bread_u64_be(stream); tb_trace_d("root_object: %lu", root_object); // read offset table index tb_size_t offset_table_index = (tb_size_t)tb_stream_bread_u64_be(stream); tb_trace_d("offset_table_index: %lu", offset_table_index); // check tb_assert_and_check_return_val(item_size && offset_size && object_count, tb_null); // init object hash tb_object_ref_t* object_hash = (tb_object_ref_t*)tb_malloc0(sizeof(tb_object_ref_t) * object_count); tb_assert_and_check_return_val(object_hash, tb_null); // done tb_bool_t failed = tb_false; do { // walk tb_size_t i = 0; for (i = 0; i < object_count; i++) { // seek to the offset entry if (!tb_stream_seek(stream, offset_table_index + i * offset_size)) { failed = tb_true; break; } // read the object offset tb_hize_t offset = 0; switch (offset_size) { case 1: offset = tb_stream_bread_u8(stream); break; case 2: offset = tb_stream_bread_u16_be(stream); break; case 4: offset = tb_stream_bread_u32_be(stream); break; case 8: offset = tb_stream_bread_u64_be(stream); break; default: return tb_null; break; } // seek to the object offset if (!tb_stream_seek(stream, offset)) { failed = tb_true; break; } // read object object_hash[i] = tb_object_bplist_reader_func_object(&reader, item_size); // if (object_hash[i]) tb_object_dump(object_hash[i]); } // failed? tb_check_break(!failed); // build array & dictionary items for (i = 0; i < object_count; i++) { tb_object_ref_t object = object_hash[i]; if (object) { switch (tb_object_type(object)) { case TB_OBJECT_TYPE_ARRAY: { // the priv data tb_byte_t* priv = (tb_byte_t*)tb_object_getp(object); if (priv) { // count tb_size_t count = (tb_size_t)tb_bits_get_u32_ne(priv); if (count) { // goto item data tb_byte_t const* p = priv + sizeof(tb_uint32_t); // walk items tb_size_t j = 0; for (i = 0; j < count; j++) { // the item index tb_size_t item = tb_object_bplist_bits_get(p + j * item_size, item_size); tb_assert(item < object_count && object_hash[item]); // tb_trace_d("item: %d", item); // append item if (item < object_count && object_hash[item]) { tb_object_inc(object_hash[item]); tb_object_array_append(object, object_hash[item]); } } } // exit priv tb_free(priv); tb_object_setp(object, tb_null); // tb_object_dump(object); } } break; case TB_OBJECT_TYPE_DICTIONARY: { // the priv data tb_byte_t* priv = (tb_byte_t*)tb_object_getp(object); if (priv) { // count tb_size_t count = (tb_size_t)tb_bits_get_u32_ne(priv); if (count) { // goto item data tb_byte_t const* p = priv + sizeof(tb_uint32_t); // walk items tb_size_t j = 0; for (i = 0; j < count; j++) { // the key & val tb_size_t key = tb_object_bplist_bits_get(p + j * item_size, item_size); tb_size_t val = tb_object_bplist_bits_get(p + (count + j) * item_size, item_size); tb_assert(key < object_count && object_hash[key]); tb_assert(val < object_count && object_hash[val]); // tb_trace_d("key_val: %u => %lu", key, val); // append the key & val if (key < object_count && val < object_count && object_hash[key] && object_hash[val]) { // key must be string now. tb_assert(tb_object_type(object_hash[key]) == TB_OBJECT_TYPE_STRING); if (tb_object_type(object_hash[key]) == TB_OBJECT_TYPE_STRING) { // set key => val tb_char_t const* skey = tb_object_string_cstr(object_hash[key]); if (skey) { tb_object_inc(object_hash[val]); tb_object_dictionary_set(object, skey, object_hash[val]); } tb_assert(skey); } } } } // exit priv tb_free(priv); tb_object_setp(object, tb_null); // tb_object_dump(object); } } break; default: break; } } } } while (0); // exit object hash if (object_hash) { // root if (root_object < object_count) root = object_hash[root_object]; // refn-- tb_size_t i; for (i = 0; i < object_count; i++) { if (object_hash[i] && i != root_object) tb_object_dec(object_hash[i]); } // exit object hash tb_free(object_hash); object_hash = tb_null; } // ok? return root; }
static tb_object_ref_t tb_object_bplist_reader_func_string(tb_object_bplist_reader_t* reader, tb_size_t type, tb_size_t size, tb_size_t item_size) { // check tb_assert_and_check_return_val(reader && reader->stream, tb_null); // init tb_char_t* utf8 = tb_null; tb_char_t* utf16 = tb_null; tb_object_ref_t object = tb_null; // read switch (type) { case TB_OBJECT_BPLIST_TYPE_STRING: { // size is too large? if (size == 0x0f) { // read size tb_long_t val = tb_object_bplist_reader_func_size(reader, item_size); tb_assert_and_check_return_val(val >= 0, tb_null); size = (tb_size_t)val; } // read string if (size) { // init utf8 utf8 = tb_malloc_cstr(size + 1); tb_assert_and_check_break(utf8); // read utf8 if (!tb_stream_bread(reader->stream, (tb_byte_t*)utf8, size)) break; utf8[size] = '\0'; } // init object object = tb_object_string_init_from_cstr(utf8); } break; case TB_OBJECT_BPLIST_TYPE_UNICODE: { #ifdef TB_CONFIG_MODULE_HAVE_CHARSET // size is too large? if (size == 0x0f) { // read size tb_long_t val = tb_object_bplist_reader_func_size(reader, item_size); tb_assert_and_check_return_val(val >= 0, tb_null); size = (tb_size_t)val; } // read string if (size) { // init utf8 & utf16 data utf8 = tb_malloc_cstr((size + 1) << 2); utf16 = tb_malloc_cstr(size << 1); tb_assert_and_check_break(utf8 && utf16); // read utf16 if (!tb_stream_bread(reader->stream, (tb_byte_t*)utf16, size << 1)) break; // utf16 to utf8 tb_long_t osize = tb_charset_conv_data(TB_CHARSET_TYPE_UTF16, TB_CHARSET_TYPE_UTF8, (tb_byte_t*)utf16, size << 1, (tb_byte_t*)utf8, (size + 1) << 2); tb_assert_and_check_break(osize > 0 && osize < (tb_long_t)((size + 1) << 2)); utf8[osize] = '\0'; // init object object = tb_object_string_init_from_cstr(utf8); } #else // trace tb_trace1_e("unicode type is not supported, please enable charset module config if you want to use it!"); #endif } break; default: break; } // exit if (utf8) tb_free(utf8); if (utf16) tb_free(utf16); // ok? return object; }