static tb_bool_t tb_oc_bplist_writer_func_array(tb_oc_bplist_writer_t* writer, tb_object_ref_t object, tb_size_t item_size) { // check tb_assert_and_check_return_val(writer && writer->stream && object, tb_false); // index tables tb_byte_t* index_tables = (tb_byte_t*)tb_object_getp(object); // size tb_size_t size = tb_oc_array_size(object); tb_assert_and_check_return_val(!size == !index_tables, tb_false); // writ flag tb_uint8_t flag = TB_OBJECT_BPLIST_TYPE_ARRAY | (size < 15 ? (tb_uint8_t)size : 0xf); if (!tb_stream_bwrit_u8(writer->stream, flag)) return tb_false; // writ size if (size >= 15) { // init osize tb_object_ref_t osize = tb_oc_bplist_writer_init_number(size); tb_assert_and_check_return_val(osize, tb_false); // writ it if (!tb_oc_bplist_writer_func_number(writer, osize, item_size)) { tb_object_exit(osize); return tb_false; } // exit osize tb_object_exit(osize); } // writ index tables if (index_tables) { if (!tb_stream_bwrit(writer->stream, index_tables, size * item_size)) return tb_false; } // ok return tb_true; }
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; }