2012-07-27 28 views
7

Tôi đang sử dụng triển khai thực hiện msgpack C++. Tôi đã gặp phải một rào cản về cách đóng gói dữ liệu nhị phân. Xét về dữ liệu nhị phân Tôi có một bộ đệm của các loại sau đây: điểmmsgpack C++ thực hiện: Làm thế nào để đóng gói dữ liệu nhị phân?

unsigned char* data; 

Dữ liệu biến để một mảng mà thực sự là một hình ảnh. Những gì tôi muốn làm là gói này bằng cách sử dụng msgpack. Dường như không có ví dụ về cách thực sự gói dữ liệu nhị phân. Từ các byte thô format specification được hỗ trợ, nhưng tôi không chắc chắn cách sử dụng chức năng.

tôi đã cố gắng sử dụng một vector của con trỏ ký tự như sau:

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

Nhưng kết quả này trong một lỗi biên dịch vì không có chức năng mẫu cho T = std :: vector.

Tôi cũng chỉ đơn giản là thử như sau:

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

Nhưng điều này cũng dẫn đến một lỗi biên dịch (tức là không có chức năng mẫu cho T = const char [6]

Vì vậy, tôi đã hy vọng một người nào đó có thể cho tôi lời khuyên về cách sử dụng msgpack C++ để đóng gói dữ liệu nhị phân được biểu thị dưới dạng một mảng char char

Trả lời

2

Nếu bạn có thể lưu trữ hình ảnh của mình trong vector<unsigned char> thay vì một mảng nguyên của unsigned char, sau đó bạn có thể đóng gói mà 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; 
} 

Kỳ lạ thay, điều này chỉ làm việc cho unsigned char. Nếu bạn cố gắng đóng gói bộ đệm char thay vào đó (hoặc thậm chí một cá nhân char), nó sẽ không biên dịch.

+0

Cảm ơn Josh. Tôi nghĩ rằng tôi đã thử điều này rồi. Thật không may với giải pháp này tôi phải sao chép rất nhiều dữ liệu nhị phân (hình ảnh) từ mảng byte để vectơ của unsigned char. Đồng thời, tôi không hoàn toàn chắc chắn lý do tại sao bạn biên soạn. Vì tôi không thấy bất kỳ chức năng nào hỗ trợ đặc biệt cho char chưa được ký. Tôi sẽ tìm hiểu sâu hơn về mã nguồn và xem liệu có cách nào hiệu quả hơn tôi có thể thực hiện việc này hay không (tức là tránh sao chép). – mdb841

+0

Ngoài ra, điều này sẽ lưu nó dưới dạng một mảng ký tự, thay vì dữ liệu nhị phân, đó là một loại khác nhau theo ... –

+1

Chỉ cần nhìn nó lên: sử dụng một vector thay vì vector dường như sử dụng loại nhị phân thay vì mảng ... –

4

Josh provided a good answer nhưng nó yêu cầu sao chép bộ đệm byte thành véc tơ char. Tôi muốn giảm thiểu việc sao chép và sử dụng bộ đệm trực tiếp (nếu có thể). Sau đây là giải pháp thay thế:

Xem qua mã nguồn và cố gắng xác định cách các loại dữ liệu khác nhau được đóng gói theo đặc điểm kỹ thuật tôi đã xảy ra khi msgpack::packer<>::pack_raw(size_t l)msgpack::packer<>::pack_raw_body(const char* b, size_t l). Mặc dù dường như không có tài liệu nào cho các phương pháp này nhưng đây là cách tôi mô tả chúng.

  1. msgpack :: packer <> :: pack_raw (size_t l): Phương pháp này gắn thêm việc xác định loại để đệm (tức là sửa chữa liệu, raw16 hoặc raw32) cũng như các thông tin kích thước (đó là một cuộc tranh cãi cho phương pháp).
  2. msgpack :: packer <> :: pack_raw_body (const char * b, size_t l): Phương pháp này gắn dữ liệu thô vào bộ đệm.

Sau đây là một ví dụ đơn giản về cách đóng gói một mảng ký tự:

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 

Ví dụ trên có thể được mở rộng để đóng gói bất kỳ dữ liệu nhị phân. Điều này cho phép một gói trực tiếp từ mảng byte/bộ đệm mà không cần phải sao chép sang một trung gian (nghĩa là một véc tơ của char).

+0

Cách giải nén tương ứng sẽ như thế nào? –

3

MessagePack có một loại raw_ref mà bạn có thể sử dụng như sau:

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

} 

Disclaimer: Tôi tìm thấy điều này bằng cách chọc xung quanh các tập tin tiêu đề, không phải thông qua đọc tài liệu không tồn tại trên serialising byte thô, vì vậy nó có thể không phải là cách 'chính xác' (mặc dù nó được định nghĩa cùng với tất cả các loại 'chuẩn' khác mà một serialiser muốn xử lý rõ ràng).

+0

Tôi vừa xác nhận rằng điều này làm việc cho tôi, ít nhất là mã hóa. Tôi cư một std :: vector , điểm raw_ref vào trong vector, và đóng gói raw_ref. Kết quả sử dụng mã loại msgpack C4, là ID cho định dạng "bin 8". – mjwach

+1

Khi giải nén, có một sự bắt buộc này: Thư viện sẽ giải nén một luồng ký tự vào raw_ref đủ tốt, nhưng sau đó nó không rõ ràng, với một người quan sát không biết gì, những gì sở hữu bộ nhớ được chỉ bởi raw_ref. Phân tích ngẫu nhiên của tôi cho thấy đó là msgpack :: cấu trúc unpacked; nếu đó là đúng thì tôi giả sử người ta phải giữ cấu trúc đó xung quanh sau khi giải nén cho miễn là raw_ref giải nén có thể cần phải được đọc. ... Nhưng có lẽ điều đó cũng đúng với các loại giải nén khác? Tôi không chắc. Thư viện này thực sự cần tài liệu tốt hơn. :( – mjwach

0

msgpack-c đã được cập nhật sau khi câu hỏi và câu trả lời đã được đăng. Tôi muốn thông báo cho tình hình hiện tại.

Kể từ mảng msgpack-c phiên bản 2.0.0 kiểu C đã được hỗ trợ. Xem https://github.com/msgpack/msgpack-c/releases

msgpack-c có thể gói mảng const char như "hello". Các loại quy tắc chuyển đổi được ghi thành tài liệu https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_adaptor#predefined-adaptors.

mảng char được ánh xạ tới STR. Nếu bạn muốn sử dụng BIN thay vì STR, bạn cần phải bọc với msgpack::type::raw_ref. Đó là tổng quan về đóng gói.

Dưới đây là giải nén và chuyển đổi mô tả: https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_object#conversion

Unpack có nghĩa là tạo msgpack::object từ MessagePack dòng định dạng byte. Chuyển đổi có nghĩa là chuyển đổi thành đối tượng C++ từ msgpack::object.

Nếu dữ liệu định dạng MessagePack là STR và loại mục tiêu bí mật là mảng char, sao chép dữ liệu vào mảng và nếu mảng có dung lượng lớn, hãy thêm '\ 0'. Nếu MessagePack định dạng dữ liệu là BIN, '\ 0' không được thêm vào.

Dưới đây là một ví dụ mã dựa trên các câu hỏi ban đầu:

#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; 
    } 
} 

Chạy Demo: https://wandbox.org/permlink/mYJyYycfsQIwsekY

Các vấn đề liên quan