Exemple #1
0
tb_handle_t g2_pcache_init(tb_size_t maxn)
{
	// check
	tb_assert_and_check_return_val(maxn, tb_null);

	// alloc
	g2_pcache_t* pcache = tb_malloc0(sizeof(g2_pcache_t));
	tb_assert_and_check_return_val(pcache, tb_null);

	// init path cache
	pcache->maxn = maxn;
	pcache->cache = tb_stack_init(maxn, tb_item_func_ptr(tb_null, tb_null));
	tb_assert_and_check_goto(pcache->cache, fail);
	while (maxn--)
	{
		// init
		tb_handle_t path = g2_path_init();
		tb_assert_and_check_goto(path, fail);

		// put
		tb_stack_put(pcache->cache, path);
	}

	// init path hash
	pcache->hash = tb_hash_init(tb_isqrti(pcache->maxn), tb_item_func_ifm(sizeof(g2_shape_t), tb_null, tb_null), tb_item_func_ptr(g2_pcache_hash_item_free, pcache));
	tb_assert_and_check_goto(pcache->hash, fail);

	// ok
	return pcache;
fail:
	if (pcache) g2_pcache_exit(pcache);
	return tb_null;
}
Exemple #2
0
/* ///////////////////////////////////////////////////////////////////////
 * initializer
 */
g2_svg_element_t* g2_svg_element_init_polygon(tb_handle_t reader)
{
	// alloc 
	g2_svg_element_polygon_t* element = tb_malloc0(sizeof(g2_svg_element_polygon_t));
	tb_assert_and_check_return_val(element, tb_null);

	// init
	element->base.exit 		= g2_svg_element_polygon_exit;
	element->base.writ 		= g2_svg_element_polygon_writ;
	element->base.fill 		= g2_svg_element_polygon_draw;
	element->base.stok 		= g2_svg_element_polygon_draw;
	element->base.clip 		= g2_svg_element_polygon_clip;
	element->base.style 	= &element->style;
	element->base.transform = &element->transform;

	// init style
	g2_svg_style_init(&element->style);

	// init transform
	g2_matrix_clear(&element->transform);

	// attributes
	tb_xml_node_t const* attr = tb_xml_reader_attributes(reader);
	for (; attr; attr = attr->next)
	{
		tb_char_t const* p = tb_pstring_cstr(&attr->data);
		if (!tb_pstring_cstricmp(&attr->name, "id"))
			tb_pstring_strcpy(&element->base.id, &attr->data);
		else if (!tb_pstring_cstricmp(&attr->name, "points"))
			g2_svg_element_polygon_points(element, p);
		else if (!tb_pstring_cstricmp(&attr->name, "style"))
			g2_svg_parser_style(p, &element->style);
		else if (!tb_pstring_cstricmp(&attr->name, "fill"))
			g2_svg_parser_style_fill(p, &element->style);
		else if (!tb_pstring_cstricmp(&attr->name, "fill-opacity"))
			g2_svg_parser_style_fill_opacity(p, &element->style);
		else if (!tb_pstring_cstricmp(&attr->name, "stroke"))
			g2_svg_parser_style_stok(p, &element->style);
		else if (!tb_pstring_cstricmp(&attr->name, "stroke-width"))
			g2_svg_parser_style_stok_width(p, &element->style);
		else if (!tb_pstring_cstricmp(&attr->name, "stroke-linecap"))
			g2_svg_parser_style_stok_linecap(p, &element->style);
		else if (!tb_pstring_cstricmp(&attr->name, "stroke-linejoin"))
			g2_svg_parser_style_stok_linejoin(p, &element->style);
		else if (!tb_pstring_cstricmp(&attr->name, "stroke-opacity"))
			g2_svg_parser_style_stok_opacity(p, &element->style);
		else if (!tb_pstring_cstricmp(&attr->name, "opacity"))
			g2_svg_parser_style_opacity(p, &element->style);
		else if (!tb_pstring_cstricmp(&attr->name, "clip-path"))
			g2_svg_parser_style_clippath(p, &element->style);
		else if (!tb_pstring_cstricmp(&attr->name, "transform"))
			g2_svg_parser_transform(p, &element->transform);
	}

	// ok
	return element;
}
Exemple #3
0
tb_handle_t g2_style_init()
{
	// alloc
	g2_style_t* gstyle = tb_malloc0(sizeof(g2_style_t));
	tb_assert_and_check_return_val(gstyle, tb_null);

	// init
	g2_style_clear(gstyle);

	// ok
	return gstyle;
}
Exemple #4
0
/* //////////////////////////////////////////////////////////////////////////////////////
 * implementation
 */
tb_mutex_ref_t tb_mutex_init()
{
    // make mutex
    pthread_mutex_t* pmutex = tb_malloc0(sizeof(pthread_mutex_t));
    tb_assert_and_check_return_val(pmutex, tb_null);

    // init mutex
    if (pthread_mutex_init(pmutex, tb_null)) return tb_null;
    
    // ok
    return ((tb_mutex_ref_t)pmutex);
}
Exemple #5
0
/* ///////////////////////////////////////////////////////////////////////
 * initializer
 */
g2_svg_element_t* g2_svg_element_init_svg(tb_handle_t reader)
{
	// alloc 
	g2_svg_element_svg_t* element = tb_malloc0(sizeof(g2_svg_element_svg_t));
	tb_assert_and_check_return_val(element, tb_null);

	// init
	element->base.writ = g2_svg_element_svg_writ;
	element->base.exit = g2_svg_element_svg_exit;

	// init painter
	element->painter.painter 	= tb_null;
	element->painter.hash 		= tb_null;
	element->painter.pool 		= tb_null;
	element->painter.load 		= tb_false;

	// attributes
	tb_size_t pw = 0;
	tb_size_t ph = 0;
	tb_xml_node_t const* attr = tb_xml_reader_attributes(reader);
	for (; attr; attr = attr->next)
	{
		tb_char_t const* p = tb_pstring_cstr(&attr->data);
		if (!tb_pstring_cstricmp(&attr->name, "x"))
			g2_svg_parser_float(p, &element->x);	
		else if (!tb_pstring_cstricmp(&attr->name, "y"))
			g2_svg_parser_float(p, &element->y);	
		else if (!tb_pstring_cstricmp(&attr->name, "width"))
		{
			p = g2_svg_parser_float(p, &element->width);
			if (*p == '%') pw = 1;
		}
		else if (!tb_pstring_cstricmp(&attr->name, "height"))
		{
			p = g2_svg_parser_float(p, &element->height);	
			if (*p == '%') ph = 1;
		}
		else if (!tb_pstring_cstricmp(&attr->name, "viewBox"))
		{
			p = g2_svg_parser_float(p, &element->viewbox.x); p = g2_svg_parser_separator_skip(p);
			p = g2_svg_parser_float(p, &element->viewbox.y); p = g2_svg_parser_separator_skip(p);
			p = g2_svg_parser_float(p, &element->viewbox.w); p = g2_svg_parser_separator_skip(p);
			p = g2_svg_parser_float(p, &element->viewbox.h);
		}
	}

	if (pw && element->viewbox.w) element->width = g2_mul(element->viewbox.w, element->width / 100);
	if (pw && element->viewbox.h) element->height = g2_mul(element->viewbox.h, element->height / 100);

	// ok
	return element;
}
Exemple #6
0
/* ///////////////////////////////////////////////////////////////////////
 * initializer
 */
g2_svg_element_t* g2_svg_element_init_image(tb_handle_t reader)
{
	// alloc 
	g2_svg_element_image_t* element = tb_malloc0(sizeof(g2_svg_element_image_t));
	tb_assert_and_check_return_val(element, tb_null);

	// init
	element->base.exit 		= g2_svg_element_image_exit;
	element->base.writ 		= g2_svg_element_image_writ;
	element->base.load 		= g2_svg_element_image_load;
	element->base.fill 		= g2_svg_element_image_draw;
	element->base.style 	= &element->style;
	element->base.transform = &element->transform;

	// init href
	tb_pstring_init(&element->href);

	// init style
	g2_svg_style_init(&element->style);

	// init transform
	g2_matrix_clear(&element->transform);

	// attributes
	tb_xml_node_t const* attr = tb_xml_reader_attributes(reader);
	for (; attr; attr = attr->next)
	{
		tb_char_t const* p = tb_pstring_cstr(&attr->data);
		if (!tb_pstring_cstricmp(&attr->name, "id"))
			tb_pstring_strcpy(&element->base.id, &attr->data);
		else if (!tb_pstring_cstricmp(&attr->name, "x"))
			g2_svg_parser_float(p, &element->rect.x);
		else if (!tb_pstring_cstricmp(&attr->name, "y"))
			g2_svg_parser_float(p, &element->rect.y);
		else if (!tb_pstring_cstricmp(&attr->name, "width"))
			g2_svg_parser_float(p, &element->rect.w);
		else if (!tb_pstring_cstricmp(&attr->name, "height"))
			g2_svg_parser_float(p, &element->rect.h);
		else if (!tb_pstring_cstricmp(&attr->name, "opacity"))
			g2_svg_parser_style_opacity(p, &element->style);
		else if (!tb_pstring_cstricmp(&attr->name, "clip-path"))
			g2_svg_parser_style_clippath(p, &element->style);
		else if (!tb_pstring_cstricmp(&attr->name, "transform"))
			g2_svg_parser_transform(p, &element->transform);
		else if (!tb_pstring_cstricmp(&attr->name, "xlink:href"))
			tb_pstring_strcpy(&element->href, &attr->data);
	}

	// ok
	return element;
}
Exemple #7
0
static tb_bool_t tb_environment_set_impl(tb_char_t const* name, tb_char_t const* value)
{
    // check
    tb_assert_and_check_return_val(name, tb_false);

    // done
    tb_bool_t   ok = tb_false;
    tb_size_t   size = 0;
    tb_wchar_t* value_w = tb_null;
    tb_size_t   value_n = 0;
    do
    {
        // make name
        tb_wchar_t  name_w[512] = {0};
        tb_size_t   name_n = tb_atow(name_w, name, tb_arrayn(name_w));
        tb_assert_and_check_break(name_n);

        // exists value?
        if (value)
        {
            // make value
            value_n = tb_strlen(value);
            value_w = (tb_wchar_t*)tb_malloc0(sizeof(tb_wchar_t) * (value_n + 1));
            tb_assert_and_check_break(value_w);

            // init value
            if (!tb_atow(value_w, value, value_n + 1)) break;

            // set it
            if (!tb_kernel32()->SetEnvironmentVariableW(name_w, value_w)) break;
        }
        // remove this variable
        else
        {
            // remove it
            if (!tb_kernel32()->SetEnvironmentVariableW(name_w, tb_null)) break;
        }

        // ok
        ok = tb_true;

    } while (0);

    // exit data
    if (value_w) tb_free(value_w);
    value_w = tb_null;

    // ok?
    return ok;
}
Exemple #8
0
/* //////////////////////////////////////////////////////////////////////////////////////
 * implementation
 */
gb_bitmap_ref_t gb_bitmap_init(tb_pointer_t data, tb_size_t pixfmt, tb_size_t width, tb_size_t height, tb_size_t row_bytes, tb_bool_t has_alpha)
{
    // done
    tb_bool_t           ok = tb_false;
    gb_bitmap_impl_t*   impl = tb_null;
    do
    {
        // check
        tb_assert_and_check_break(GB_PIXFMT_OK(pixfmt));
        tb_assert_and_check_break(width && width <= GB_WIDTH_MAXN && height && height <= GB_HEIGHT_MAXN);

        // make bitmap
        impl = tb_malloc0_type(gb_bitmap_impl_t);
        tb_assert_and_check_break(impl);

        // the pixmap, only using btp
        gb_pixmap_ref_t pixmap = gb_pixmap(pixfmt, 0xff);
        tb_assert_and_check_break(pixmap);

        // the row bytes
        if (!row_bytes) row_bytes = width * pixmap->btp;
        tb_assert_and_check_break(row_bytes && row_bytes >= width * pixmap->btp);

        // init bitmap 
        impl->pixfmt        = (tb_uint16_t)pixfmt;
        impl->width 	    = (tb_uint16_t)width;
        impl->height 	    = (tb_uint16_t)height;
        impl->row_bytes 	= (tb_uint16_t)row_bytes;
        impl->size 	        = row_bytes * height;
        impl->data          = data? data : tb_malloc0(impl->size);
        impl->has_alpha     = !!has_alpha;
        impl->is_owner      = !data;
        tb_assert_and_check_break(impl->data);

        // ok
        ok = tb_true;

    } while (0);

    // failed?
    if (!ok)
    {
        // exit it
        if (impl) gb_bitmap_exit((gb_bitmap_ref_t)impl);
        impl = tb_null;
    }

    // ok?
    return (gb_bitmap_ref_t)impl;
}
Exemple #9
0
static tb_aiop_rtor_impl_t* tb_aiop_rtor_kqueue_init(tb_aiop_impl_t* aiop)
{
    // check
    tb_assert_and_check_return_val(aiop && aiop->maxn, tb_null);

    // done
    tb_bool_t                   ok = tb_false;
    tb_aiop_rtor_kqueue_impl_t* impl = tb_null;
    do
    {
        // make impl
        impl = tb_malloc0(sizeof(tb_aiop_rtor_kqueue_impl_t));
        tb_assert_and_check_break(impl);

        // init base
        impl->base.aiop = aiop;
        impl->base.code = TB_AIOE_CODE_EALL | TB_AIOE_CODE_CLEAR | TB_AIOE_CODE_ONESHOT;
        impl->base.exit = tb_aiop_rtor_kqueue_exit;
        impl->base.cler = tb_aiop_rtor_kqueue_cler;
        impl->base.addo = tb_aiop_rtor_kqueue_addo;
        impl->base.delo = tb_aiop_rtor_kqueue_delo;
        impl->base.post = tb_aiop_rtor_kqueue_post;
        impl->base.wait = tb_aiop_rtor_kqueue_wait;

        // init kqueue
        impl->kqfd = kqueue();
        tb_assert_and_check_break(impl->kqfd >= 0);

        // ok
        ok = tb_true;

    } while (0);

    // failed?
    if (!ok)
    {
        // exit it
        if (impl) tb_aiop_rtor_kqueue_exit((tb_aiop_rtor_impl_t*)impl);
        impl = tb_null;
    }

    // ok?
    return (tb_aiop_rtor_impl_t*)impl;
}
Exemple #10
0
/* //////////////////////////////////////////////////////////////////////////////////////
 * private implementation
 */
static tb_char_t* tb_environment_get_impl(tb_char_t const* name, tb_size_t* psize)
{
    // check
    tb_assert_and_check_return_val(name, 0);

    // done
    tb_bool_t   ok = tb_false;
    tb_size_t   size = 0;
    tb_size_t   maxn = 256;
    tb_char_t*  value = tb_null;
    tb_wchar_t* value_w = tb_null;
    do
    {
        // make value_w
        value_w = (tb_wchar_t*)tb_malloc0(sizeof(tb_wchar_t) * maxn);
        tb_assert_and_check_break(value_w);

        // make name
        tb_wchar_t  name_w[512];
        tb_size_t   name_n = tb_atow(name_w, name, tb_arrayn(name_w));
        tb_assert_and_check_break(name_n != -1);

        // get it
        size = (tb_size_t)tb_kernel32()->GetEnvironmentVariableW(name_w, value_w, (DWORD)maxn);
        if (!size) 
        {
            // error?
            if (ERROR_ENVVAR_NOT_FOUND == GetLastError())
            {
                // trace
                tb_trace_d("environment variable(%s) does not exist", name);
            }

            break;
        }
        else if (size > maxn)
        {
            // grow space 
            value_w = (tb_wchar_t*)tb_ralloc(value_w, sizeof(tb_wchar_t) * (size + 1));
            tb_assert_and_check_break(value_w);

            // get it
            size = (tb_size_t)tb_kernel32()->GetEnvironmentVariableW(name_w, value_w, (DWORD)size + 1);
            tb_assert_and_check_break(size);
        }

        // make value
        value = (tb_char_t*)tb_malloc0(sizeof(tb_char_t) * (size + 1));
        tb_assert_and_check_break(value);

        // save value
        if ((size = tb_wtoa(value, value_w, size)) == -1) break;

        // save size
        if (psize) *psize = size;

        // ok
        ok = tb_true;

    } while (0);

    // failed?
    if (!ok)
    {
        // exit value
        if (value) tb_free(value);
        value = tb_null;
    }

    // exit value_w
    if (value_w) tb_free(value_w);
    value_w = tb_null;

    // ok?
    return value;
}
Exemple #11
0
tb_size_t tb_hash_map_insert(tb_hash_map_ref_t hash_map, tb_cpointer_t name, tb_cpointer_t data)
{
    // check
    tb_hash_map_impl_t* impl = (tb_hash_map_impl_t*)hash_map;
    tb_assert_and_check_return_val(impl, 0);

    // the step
    tb_size_t step = impl->element_name.size + impl->element_data.size;
    tb_assert_and_check_return_val(step, 0);

    // find it
    tb_size_t buck = 0;
    tb_size_t item = 0;
    if (tb_hash_map_item_find(impl, name, &buck, &item))
    {
        // check
        tb_assert_and_check_return_val(buck < impl->hash_size, 0);

        // get list
        tb_hash_map_item_list_t* list = impl->hash_list[buck];
        tb_assert_and_check_return_val(list && list->size && item < list->size, 0);

        // replace data
        impl->element_data.repl(&impl->element_data, ((tb_byte_t*)&list[1]) + item * step + impl->element_name.size, data);
    }
    else
    {
        // check
        tb_assert_and_check_return_val(buck < impl->hash_size, 0);

        // get list
        tb_hash_map_item_list_t* list = impl->hash_list[buck];
        
        // insert item
        if (list)
        {
            // grow?
            if (list->size >= list->maxn)
            {
                // check
                tb_assert_and_check_return_val(impl->item_grow, 0);

                // resize maxn
                tb_size_t maxn = tb_align_pow2(list->maxn + impl->item_grow);
                tb_assert_and_check_return_val(maxn > list->maxn, 0);

                // realloc it
                list = (tb_hash_map_item_list_t*)tb_ralloc(list, sizeof(tb_hash_map_item_list_t) + maxn * step);  
                tb_assert_and_check_return_val(list, 0);

                // update the impl item maxn
                impl->item_maxn += maxn - list->maxn;

                // update maxn
                list->maxn = maxn;

                // reattach list
                impl->hash_list[buck] = list;
            }
            tb_assert_and_check_return_val(item <= list->size && list->size < list->maxn, 0);

            // move items
            if (item != list->size) tb_memmov(((tb_byte_t*)&list[1]) + (item + 1) * step, ((tb_byte_t*)&list[1]) + item * step, (list->size - item) * step);

            // dupl item
            list->size++;
            impl->element_name.dupl(&impl->element_name, ((tb_byte_t*)&list[1]) + item * step, name);
            impl->element_data.dupl(&impl->element_data, ((tb_byte_t*)&list[1]) + item * step + impl->element_name.size, data);

        }
        // create list for adding item
        else
        {
            // check
            tb_assert_and_check_return_val(impl->item_grow, 0);

            // make list
            list = (tb_hash_map_item_list_t*)tb_malloc0(sizeof(tb_hash_map_item_list_t) + impl->item_grow * step);
            tb_assert_and_check_return_val(list, 0);

            // init list
            list->size = 1;
            list->maxn = impl->item_grow;
            impl->element_name.dupl(&impl->element_name, ((tb_byte_t*)&list[1]), name);
            impl->element_data.dupl(&impl->element_data, ((tb_byte_t*)&list[1]) + impl->element_name.size, data);

            // attach list
            impl->hash_list[buck] = list;

            // update the impl item maxn
            impl->item_maxn += list->maxn;
        }

        // update the impl item size
        impl->item_size++;
    }

    // ok?
    return tb_hash_map_index_make(buck + 1, item + 1);
}
Exemple #12
0
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;
}