8

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

unsigned char* data;

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

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

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

4 回答 4

5

Josh提供了一个很好的答案,但它需要将字节缓冲区复制到 char 向量。我宁愿尽量减少复制并直接使用缓冲区(如果可能的话)。以下是替代解决方案:

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

  1. msgpack::packer<>::pack_raw(size_t l):此方法将类型标识附加到缓冲区(即修复 raw、raw16 或 raw32)以及大小信息(这是该方法的参数)。
  2. msgpack::packer<>::pack_raw_body(const char* b, size_t l):此方法将原始数据附加到缓冲区。

下面是一个如何打包字符数组的简单示例:

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

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

于 2012-07-30T15:28:09.260 回答
3

如果您可以将图像存储在 avector<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),它将无法编译。

于 2012-07-28T02:38:56.330 回答
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;

}

免责声明:我通过查看头文件而不是通过阅读不存在的关于序列化原始字节的文档发现了这一点,因此它可能不是“正确”的方式(尽管它与所有其他“标准”类型一起定义的序列化程序想要显式处理)。

于 2013-07-20T22:02:56.647 回答
1

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

从 msgpack-c 版本 2.0.0 开始支持 C 样式数组。见https://github.com/msgpack/msgpack-c/releases

msgpack-c 可以打包 const char 数组,例如“hello”。类型转换规则记录在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

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

如果MessagePack 格式的数据是STR,并且隐蔽的目标类型是char 数组,则将数据复制到数组中,如果数组有多余的容量,则添加'\0'。如果 MessagePack 格式的数据是 BIN,则不添加“\0”。

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

#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

于 2017-05-31T04:29:00.013 回答