tb_double_t tb_option_item_double(tb_option_ref_t option, tb_char_t const* name) { // check tb_option_impl_t* impl = (tb_option_impl_t*)option; tb_assert_and_check_return_val(impl && impl->list && name, 0); // the option item tb_object_ref_t item = tb_oc_dictionary_value(impl->list, name); tb_check_return_val(item, 0); tb_assert_and_check_return_val(tb_object_type(item) == TB_OBJECT_TYPE_NUMBER, 0); // the option item value return tb_oc_number_double(item); }
tb_bool_t tb_option_item_bool(tb_option_ref_t option, tb_char_t const* name) { // check tb_option_impl_t* impl = (tb_option_impl_t*)option; tb_assert_and_check_return_val(impl && impl->list && name, tb_false); // the option item tb_object_ref_t item = tb_oc_dictionary_value(impl->list, name); tb_check_return_val(item, tb_false); tb_assert_and_check_return_val(tb_object_type(item) == TB_OBJECT_TYPE_BOOLEAN, tb_false); // the option item value return tb_oc_boolean_bool(item); }
tb_char_t const* tb_option_item_cstr(tb_option_ref_t option, tb_char_t const* name) { // check tb_option_impl_t* impl = (tb_option_impl_t*)option; tb_assert_and_check_return_val(impl && impl->list && name, tb_null); // the option item tb_object_ref_t item = tb_oc_dictionary_value(impl->list, name); tb_check_return_val(item, tb_null); tb_assert_and_check_return_val(tb_object_type(item) == TB_OBJECT_TYPE_STRING, tb_null); // the option item value return tb_oc_string_size(item)? tb_oc_string_cstr(item) : tb_null; }
static tb_long_t tb_object_bplist_reader_func_size(tb_object_bplist_reader_t* reader, tb_size_t item_size) { // check tb_assert_and_check_return_val(reader && reader->stream, -1); // read size tb_object_ref_t object = tb_object_bplist_reader_func_object(reader, item_size); tb_assert_and_check_return_val(object, -1); tb_long_t size = -1; if (tb_object_type(object) == TB_OBJECT_TYPE_NUMBER) size = tb_object_number_uint32(object); // exit tb_object_exit(object); // size return size; }
tb_object_ref_t tb_object_seek(tb_object_ref_t object, tb_char_t const* path, tb_size_t type) { // check tb_assert_and_check_return_val(object, tb_null); // null? tb_check_return_val(path, object); // walk tb_char_t const* p = path; tb_char_t const* e = path + tb_strlen(path); while (p < e && object) { // done seek switch (*p) { case '.': { // check tb_assert_and_check_return_val(tb_object_type(object) == TB_OBJECT_TYPE_DICTIONARY, tb_null); // skip p++; // read the key name tb_char_t key[4096] = {0}; tb_char_t* kb = key; tb_char_t* ke = key + 4095; for (; p < e && kb < ke && *p && (*p != '.' && *p != '[' && *p != ']'); p++, kb++) { if (*p == '\\') p++; *kb = *p; } // trace tb_trace_d("key: %s", key); // the value object = tb_object_dictionary_val(object, key); } break; case '[': { // check tb_assert_and_check_return_val(tb_object_type(object) == TB_OBJECT_TYPE_ARRAY, tb_null); // skip p++; // read the item index tb_char_t index[32] = {0}; tb_char_t* ib = index; tb_char_t* ie = index + 31; for (; p < e && ib < ie && *p && tb_isdigit10(*p); p++, ib++) *ib = *p; // trace tb_trace_d("index: %s", index); // check tb_size_t i = tb_atoi(index); tb_assert_and_check_return_val(i < tb_object_array_size(object), tb_null); // the value object = tb_object_array_item(object, i); } break; case ']': default: p++; break; } } // check it, if not none if (object && type != TB_OBJECT_TYPE_NONE) { // is this type? if (tb_object_type(object) != type) return tb_null; } // ok? return object; }
tb_object_ref_t tb_object_seek(tb_object_ref_t object, tb_char_t const* path, tb_bool_t bmacro) { // check tb_assert_and_check_return_val(object, tb_null); // null? tb_check_return_val(path, object); // done tb_object_ref_t root = object; tb_char_t const* p = path; tb_char_t const* e = path + tb_strlen(path); while (p < e && object) { // done seek switch (*p) { case '.': { // check tb_assert_and_check_return_val(tb_object_type(object) == TB_OBJECT_TYPE_DICTIONARY, tb_null); // skip p++; // read the key name tb_char_t key[4096] = {0}; tb_char_t* kb = key; tb_char_t* ke = key + 4095; for (; p < e && kb < ke && *p && (*p != '.' && *p != '[' && *p != ']'); p++, kb++) { if (*p == '\\') p++; *kb = *p; } // trace tb_trace_d("key: %s", key); // the value object = tb_object_dictionary_value(object, key); } break; case '[': { // check tb_assert_and_check_return_val(tb_object_type(object) == TB_OBJECT_TYPE_ARRAY, tb_null); // skip p++; // read the item index tb_char_t index[32] = {0}; tb_char_t* ib = index; tb_char_t* ie = index + 31; for (; p < e && ib < ie && *p && tb_isdigit10(*p); p++, ib++) *ib = *p; // trace tb_trace_d("index: %s", index); // check tb_size_t i = tb_atoi(index); tb_assert_and_check_return_val(i < tb_object_array_size(object), tb_null); // the value object = tb_object_array_item(object, i); } break; case ']': default: p++; break; } // is macro? done it if be enabled if ( object && bmacro && tb_object_type(object) == TB_OBJECT_TYPE_STRING && tb_object_string_size(object) && tb_object_string_cstr(object)[0] == '$') { // the next path path = tb_object_string_cstr(object) + 1; // continue to seek it object = tb_object_seek(root, path, bmacro); } } // ok? return object; }
static tb_object_ref_t tb_object_bin_reader_func_dictionary(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_dictionary_init(TB_OBJECT_DICTIONARY_SIZE_MICRO, tb_false); // init dictionary tb_object_ref_t dictionary = tb_object_dictionary_init(0, tb_false); tb_assert_and_check_return_val(dictionary, tb_null); // walk tb_size_t i = 0; tb_size_t n = (tb_size_t)size; for (i = 0; i < n; i++) { // read key tb_object_ref_t key = tb_null; do { // the type & size tb_size_t type = 0; tb_uint64_t size = 0; tb_object_reader_bin_type_size(reader->stream, &type, &size); // trace tb_trace_d("key: type: %lu, size: %llu", type, size); // is index? if (!type) { // the object index tb_size_t index = (tb_size_t)size; // check tb_assert_and_check_break(index < tb_vector_size(reader->list)); // the item key = (tb_object_ref_t)tb_iterator_item(reader->list, index); } else { // check tb_assert_and_check_break(type == TB_OBJECT_TYPE_STRING); // the reader func tb_object_bin_reader_func_t func = tb_object_bin_reader_func(type); tb_assert_and_check_break(func); // read it key = func(reader, type, size); tb_assert_and_check_break(key); // save it tb_vector_insert_tail(reader->list, key); // refn-- tb_object_dec(key); } } while (0); // check tb_assert_and_check_break(key && tb_object_type(key) == TB_OBJECT_TYPE_STRING); tb_assert_and_check_break(tb_object_string_size(key) && tb_object_string_cstr(key)); // read val tb_object_ref_t val = tb_null; do { // the type & size tb_size_t type = 0; tb_uint64_t size = 0; tb_object_reader_bin_type_size(reader->stream, &type, &size); // trace tb_trace_d("val: type: %lu, size: %llu", type, size); // is index? if (!type) { // the object index tb_size_t index = (tb_size_t)size; // check tb_assert_and_check_break(index < tb_vector_size(reader->list)); // the item val = (tb_object_ref_t)tb_iterator_item(reader->list, index); // refn++ if (val) tb_object_inc(val); } else { // the reader func tb_object_bin_reader_func_t func = tb_object_bin_reader_func(type); tb_assert_and_check_break(func); // read it val = func(reader, type, size); // save it if (val) tb_vector_insert_tail(reader->list, val); } } while (0); // check tb_assert_and_check_break(val); // set key => val tb_object_dictionary_set(dictionary, tb_object_string_cstr(key), val); } // failed? if (i != n) { if (dictionary) tb_object_exit(dictionary); dictionary = tb_null; } // ok? return dictionary; }
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; }