2012-07-27 300 views
7

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

unsigned char* data; 

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

我试图用字符指针的向量类似如下:

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

但是由于没有用于T =的std ::向量没有函数模板这将导致一个编译器错误。

我也简单地尝试了以下内容:

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

但是,这也导致了一个编译错误(即,对于T =常量字符[6]

因此没有功能模板,我希望有人可以告诉我如何使用msgpack C++来打包二进制数据,如char array

回答

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),它将不会编译。

+0

感谢约什。我以为我已经尝试过了。不幸的是,用这个解决方案,我必须将大量的二进制数据(图像)从字节数组复制到无符号字符的向量中。另外,我不完全确定你为什么编译。因为我没有看到任何特别支持unsigned char的函数。我将深入研究源代码,看看是否有更高效的方式来完成这项工作(即避免复制)。 – mdb841 2012-07-30 13:19:10

+0

此外,这将它保存为一个字符数组,而不是二进制数据,根据实现它是一个不同的类型... – 2015-06-03 13:03:29

+1

只是查了一下:使用矢量而不是矢量似乎使用二进制类型,而不是数组... – 2015-06-03 13:37:43

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 ::打包机<> :: pack_raw(为size_t升):此方法追加类型识别为缓冲(即固定原料,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的向量)。

+0

相应的拆包会是什么样子? – 2016-02-24 01:52:04

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; 

} 

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

+0

我刚刚证实,至少在编码方面,这对我很有用。我填充std :: vector ,将raw_ref指向vector,并打包raw_ref。结果使用msgpack类型代码C4,它是“bin 8”格式的ID。 – mjwach 2015-08-06 19:07:11

+1

关于解包,有一个问题:库会将字符流解压到raw_ref中,但对于一个无知的观察者来说,它不清楚raw_ref所指向的内存是什么。我的随意分析表明它是msgpack :: unpacked结构;如果这是正确的,那么我认为只要解压缩的raw_ref可能需要被读取,就必须在解包之后保持这种结构。 ...但是也许这对其他解包类型也是如此?我不确定。这个库确实需要更好的文档。 :( – mjwach 2015-08-06 19:11:17

0

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

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

msgpack-c可以打包常量字符数组,如“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

拆开意味着创建从MessagePack格式化字节流msgpack::object。转换意味着从msgpack::object转换为C++对象。

如果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