8

私は C++ msgpack 実装を利用しています。バイナリ データをパックする方法について、障害が発生しました。バイナリデータに関しては、次のタイプのバッファがあります。

unsigned char* data;

データ変数は、実際には画像である配列を指します。私がやりたいのは、これを msgpack を使用してパックすることです。実際にバイナリデータをパックする方法の例はないようです。フォーマット仕様からraw バイトがサポートされていますが、機能を利用する方法がわかりません。

次のような文字ポインターのベクトルを使用してみました。

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):このメソッドは、タイプIDをバッファー(つまり、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のベクトル)にコピーすることなく、バイト配列/バッファーから直接パックすることができます。

于 2012-07-30T15:28:09.260 に答える
3

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と、コンパイルされません。

于 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;

}

免責事項:これは、生バイトのシリアル化に関する存在しないドキュメントを読むことではなく、ヘッダーファイルを調べて見つけたので、「正しい」方法ではない可能性があります(ただし、他のすべての「標準」タイプとともに定義されていましserialiser は明示的に処理する必要があります)。

于 2013-07-20T22:02:56.647 に答える
1

msgpack-c は、質問と回答が投稿された後に更新されました。現在の状況をお知らせしたいと思います。

msgpack-c バージョン 2.0.0 以降、C スタイルの配列がサポートされています。https://github.com/msgpack/msgpack-c/releasesを参照してください

msgpack-c は、"hello" などの const char 配列をパックできます。型変換ルールはhttps://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_adaptor#predefined-adaptorsに記載されています。

char 配列は STR にマップされます。STR の代わりに BIN を使用する場合は、でラップする必要がありますmsgpack::type::raw_ref。以上が梱包概要です。

解凍と変換の説明は次のとおりです: https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_object#conversion

msgpack::objectアンパックとは、MessagePack 形式のバイト ストリームから作成することを意味します。Convert とは、 から 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 に答える