msgpack C ++实现:如何打包二进制数据?

时间:2012-07-27 19:47:37

标签: c++ msgpack

我正在使用C ++ msgpack实现。关于如何打包二进制数据,我遇到了障碍。就二进制数据而言,我有一个以下类型的缓冲区:

unsigned char* data;

数据变量指向一个实际上是图像的数组。我想要做的是使用msgpack打包。似乎没有关于如何实际打包二进制数据的示例。支持format specification原始字节,但我不确定如何使用该功能。

我尝试使用如下字符指针的向量:

msgpack::sbuffer temp_sbuffer;
std::vector<char*> vec;
msgpack::pack(temp_sbuffer, vec);

但由于 T = std :: vector 没有函数模板,因此会导致编译错误。

我还尝试了以下内容:

msgpack::pack(temp_sbuffer, "Hello");

但这也会导致编译错误(即 T = const char [6]

没有函数模板

因此,我希望有人可以就如何使用msgpack C ++打包表示为 char 数组的二进制数据提供建议。

4 个答案:

答案 0 :(得分:4)

Josh provided a good answer但它需要将字节缓冲区复制到char矢量。我宁愿最小化复制并直接使用缓冲区(如果可能的话)。以下是另一种解决方案:

查看源代码并尝试根据msgpack::packer<>::pack_raw(size_t l)msgpack::packer<>::pack_raw_body(const char* b, size_t l)上发生的规范确定如何打包不同的数据类型。虽然似乎没有这些方法的文档,但这就是我对它们的描述。

  1. msgpack :: packer&lt;&gt; :: pack_raw(size_t l):此方法将类型标识附加到缓冲区(即修复raw,raw16或raw32)以及大小信息(是方法的论据。)
  2. msgpack :: packer&lt;&gt; :: pack_raw_body(const char * b,size_t l):此方法将原始数据附加到缓冲区。
  3. 以下是如何打包字符数组的简单示例:

    msgpack::sbuffer temp_sbuffer;
    msgpack::packer<msgpack::sbuffer> packer(&temp_sbuffer);
    packer.pack_raw(5);  // Indicate that you are packing 5 raw bytes
    packer.pack_raw_body("Hello", 5); // Pack the 5 bytes
    

    上面的示例可以扩展为打包任何二进制数据。这允许直接从字节数组/缓冲区打包而不必复制到中间数(即char的向量)。

答案 1 :(得分:3)

MessagePack有raw_ref类型,您可以这样使用:

#include "msgpack.hpp"

class myClass
{
public:
    msgpack::type::raw_ref r;
    MSGPACK_DEFINE(r);
};

int _tmain(int argc, _TCHAR* argv[])
{
    const char* str = "hello";

    myClass c;

    c.r.ptr = str;
    c.r.size = 6;

    // From here on down its just the standard MessagePack example...

    msgpack::sbuffer sbuf;
    msgpack::pack(sbuf, c);

    msgpack::unpacked msg;
    msgpack::unpack(&msg, sbuf.data(), sbuf.size());

    msgpack::object o = msg.get();

    myClass d;
    o.convert(&d);

    OutputDebugStringA(d.r.ptr);

    return 0;

}

免责声明:我通过查看头文件找到了这个,而不是通过阅读序列化原始字节的不存在的文档,所以它可能不是'正确'的方式(虽然它 定义以及序列化程序希望显式处理的所有其他“标准”类型。)

答案 2 :(得分:2)

如果您可以将图片存储在vector<unsigned char>而不是unsigned char的原始数组中,那么您可以打包vector

#include <iostream>
#include <string>
#include <vector>
#include <msgpack.hpp>

int main()
{
    std::vector<unsigned char> data;
    for (unsigned i = 0; i < 10; ++i)
        data.push_back(i * 2);

    msgpack::sbuffer sbuf;
    msgpack::pack(sbuf, data);

    msgpack::unpacked msg;
    msgpack::unpack(&msg, sbuf.data(), sbuf.size());

    msgpack::object obj = msg.get();
    std::cout << obj << std::endl;
}

奇怪的是,这只适用于unsigned char。如果您尝试打包char的缓冲区(甚至是个人char),它将无法编译。

答案 3 :(得分:0)

在问题和答案发布后,msgpack-c已更新。 我想告知目前的情况。

由于支持msgpack-c版本2.0.0 C风格的数组。见https://github.com/msgpack/msgpack-c/releases

msgpack -c可以打包const char数组,例如&#34; hello&#34;。 类型转换规则记录在https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_adaptor#predefined-adaptors

char数组映射到STR。如果您想使用BIN而不是STR,则需要使用msgpack::type::raw_ref换行。 这是包装概述。

以下是拆包和转换说明: https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_object#conversion

解包意味着从MessagePack格式的字节流创建msgpack::object。转换意味着从msgpack::object转换为C ++对象。

如果MessagePack格式化数据为STR,隐蔽目标类型为char数组,则将数据复制到数组,如果数组有额外容量,则添加&#39; \ 0&#39;。如果MessagePack格式的数据是BIN,则&#39; \ 0&#39;没有添加。

以下是基于原始问题的代码示例:

#include <msgpack.hpp>
#include <iostream>

inline
std::ostream& hex_dump(std::ostream& o, char const* p, std::size_t size ) {
    o << std::hex << std::setw(2) << std::setfill('0');
    while(size--) o << (static_cast<int>(*p++) & 0xff) << ' ';
    return o;
}

int main() {
    {
        msgpack::sbuffer temp_sbuffer;
        // since 2.0.0 char[] is supported.
        // See https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_adaptor#predefined-adaptors
        msgpack::pack(temp_sbuffer, "hello");
        hex_dump(std::cout, temp_sbuffer.data(), temp_sbuffer.size()) << std::endl;

        // packed as STR See https://github.com/msgpack/msgpack/blob/master/spec.md
        // '\0' is not packed
        auto oh = msgpack::unpack(temp_sbuffer.data(), temp_sbuffer.size());
        static_assert(sizeof("hello") == 6, "");
        char converted[6];
        converted[5] = 'x'; // to check overwriting, put NOT '\0'.
        // '\0' is automatically added if char-array has enought size and MessagePack format is STR
        oh.get().convert(converted); 
        std::cout << converted << std::endl;
    }
    {
        msgpack::sbuffer temp_sbuffer;
        // since 2.0.0 char[] is supported.
        // See https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_adaptor#predefined-adaptors
        // packed as BIN
        msgpack::pack(temp_sbuffer, msgpack::type::raw_ref("hello", 5));
        hex_dump(std::cout, temp_sbuffer.data(), temp_sbuffer.size()) << std::endl;

        auto oh = msgpack::unpack(temp_sbuffer.data(), temp_sbuffer.size());
        static_assert(sizeof("hello") == 6, "");
        char converted[7];
        converted[5] = 'x';
        converted[6] = '\0';
        // only first 5 bytes are written if MessagePack format is BIN
        oh.get().convert(converted);
        std::cout << converted << std::endl;
    }
}

运行演示: https://wandbox.org/permlink/mYJyYycfsQIwsekY