繁体   English   中英

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

[英]msgpack C++ implementation: How to pack binary data?

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

unsigned char* 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数组的二进制数据给出建议。

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

查看源代码并尝试根据我在msgpack::packer<>::pack_raw(size_t l)msgpack::packer<>::pack_raw_body(const char* b, size_t l) 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

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

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;

}

免责声明:我,而不是通过阅读连载原始字节不存在的文件发现这周围的头文件戳,所以它可能不会是“正确”的方式(尽管它所有其他“标准”类型一起定义的serialiser想要​​显式处理)。

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

在问题和答案发布后,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进行换msgpack::type::raw_ref 这是包装概述。

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

解包意味着从MessagePack格式的字节流创建msgpack::object 转换意味着从msgpack::object转换为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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM