ludocode / mpack

MPack - A C encoder/decoder for the MessagePack serialization format / msgpack.org[C]
MIT License
521 stars 82 forks source link

get nothing if prev node is nil #91

Closed wukan1986 closed 2 years ago

wukan1986 commented 2 years ago

Hi, Thank you for your work.

this is my code:

int main()
{
    mpack_writer_t writer;
    char* out;
    size_t size;

    mpack_writer_init_growable(&writer, &out, &size);
    mpack_start_map(&writer, 5);
    mpack_write_cstr(&writer, "A");
    mpack_write_cstr_or_nil(&writer, "11");
    mpack_write_cstr(&writer, "B");
    mpack_write_cstr_or_nil(&writer, "22"); 
    mpack_write_cstr(&writer, "C");
    mpack_write_cstr_or_nil(&writer, nullptr); // for test
    mpack_write_cstr(&writer, "D");
    mpack_write_cstr_or_nil(&writer, "44");
    mpack_write_cstr(&writer, "E");
    mpack_write_cstr_or_nil(&writer, "55");
    mpack_finish_map(&writer);

    // finish writing
    if (mpack_writer_destroy(&writer) != mpack_ok) {
        fprintf(stderr, "An error occurred encoding the data!\n");
        return -1;
    }

    mpack_tree_t tree;
    mpack_tree_init(&tree, out, size);
    mpack_tree_parse(&tree);
    mpack_node_t root = mpack_tree_root(&tree);

    for (size_t i = 0; i < 5; ++i)
    {
        char key[] = "A";
        key[0] += i;
        auto node_1 = mpack_node_map_cstr(root, key);
        auto len_1 = mpack_node_strlen(node_1);
        auto str_1 = mpack_node_str(node_1);
        std::cout << std::string(str_1, len_1) << std::endl;
    }
}

the output is:

11 22

I expect is

11 22 44 55

wukan1986 commented 2 years ago

same problem with expect api

mpack_reader_t reader;

mpack_expect_map_match(&reader, 5);

mpack_expect_cstr_match(&reader, "A");
char buf1[128] = { 0 };
mpack_expect_utf8_cstr(&reader, buf1, sizeof(buf1));

mpack_expect_cstr_match(&reader, "B");
char buf2[128] = { 0 };
mpack_expect_utf8_cstr(&reader, buf2, sizeof(buf2));

// ......

mpack_done_map(&reader);
ludocode commented 2 years ago

This behaviour may be a bit counter-intuitive in your example but it is intentional. When you call mpack_node_strlen() on a node, that node is expected to be a string. If it isn't, it means the data must be corrupt: the whole tree is placed in an error state and all subsequent calls on the tree return safe nil/zero values. This guarantees that the data matches the hardcoded schema you are expecting and your app won't crash if it doesn't. If you check the tree for errors after parsing you would get mpack_error_type because there was a nil node where a str was expected. The same happens with mpack_expect_utf8_cstr().

If you want to avoid flagging an error, call mpack_node_is_nil() first.

    for (size_t i = 0; i < 5; ++i)
    {
        char key[] = "A";
        key[0] += i;
        auto node_1 = mpack_node_map_cstr(root, key);
        if (mpack_node_is_nil(node_1)) {
            std::cout << "NIL" << std::endl;
        } else {
            auto len_1 = mpack_node_strlen(node_1);
            auto str_1 = mpack_node_str(node_1);
            std::cout << std::string(str_1, len_1) << std::endl;
        }
    }

This prints:

11
22
NIL
44
55
wukan1986 commented 2 years ago

I got it Thank you very mush