MessagePack for C++で、MFCのCStringを含むユーザー定義型をシリアライズ

できたっぽい。


CStringPack.h

#ifndef MSGPACK_TYPE_MFC_CSTRING_INCLUDE
#define MSGPACK_TYPE_MFC_CSTRING_INCLUDE

#include "msgpack/object.hpp"
#include <string>
#include "StringUtil.h" // ToMultStr, ToWideStr

namespace msgpack {


inline CStringW& operator>> (object o, CStringW& v)
{
    if(o.type != type::RAW) { throw type_error(); }
    std::string s;
    s.assign(o.via.raw.ptr, o.via.raw.size);
    v = ToWideStr(s).c_str();
    return v;
}

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, const CStringW& v)
{
    const std::string s = ToMultStr(static_cast<LPCTSTR>(v));
    o.pack_raw(s.size());
    o.pack_raw_body(s.data(), s.size());
    return o;
}

inline void operator<< (object::with_zone& o, const CStringW& v)
{
    o.type = type::RAW;
    const std::string s = ToMultStr(static_cast<LPCTSTR>(v));
    char* ptr = (char*)o.zone->malloc(s.size());
    o.via.raw.ptr = ptr;
    o.via.raw.size = (uint32_t)s.size();
    memcpy(ptr, s.data(), s.size());
}

inline void operator<< (object& o, const CStringW& v)
{
    const std::string s = ToMultStr(static_cast<LPCTSTR>(v));
    o.type = type::RAW;
    o.via.raw.ptr = s.data();
    o.via.raw.size = (uint32_t)s.size();
}


}  // namespace msgpack

#endif // MSGPACK_TYPE_MFC_CSTRING_INCLUDE
#include "stdafx.h"
#include <msgpack.hpp>
#include "CStringPack.h"
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <boost/range/algorithm/for_each.hpp>
#include <boost/bind.hpp>

class Data {
    int id;
    CStringW name;
public:
    Data() : id(0) {}
    Data(int id, const CStringW& name)
        : id(id), name(name) {}

    void print() const
    {
        std::cout << id << std::endl;
        AfxMessageBox(name);
    }

    MSGPACK_DEFINE(id, name);
};

int main()
{
    // シリアライズ
    {
        std::vector<Data> vec;
        vec.push_back(Data(1, L"abc"));
        vec.push_back(Data(2, L"あいうえお"));

        std::ofstream file("data.mpac");
        msgpack::pack(&file, vec);
    }

    // デシリアライズ
    {
        std::ifstream file("data.mpac");
        std::istreambuf_iterator<char> first(file);
        std::istreambuf_iterator<char> last;

        const std::string data(first, last);

        try {
            msgpack::unpacked msg;
            msgpack::unpack(&msg, data.data(), data.size());

            msgpack::object obj = msg.get();
            const std::vector<Data> vec = obj.as<std::vector<Data> >();

            boost::for_each(vec, boost::bind(&Data::print, _1));
        }
        catch (msgpack::unpack_error&) {
            std::cout << "unpack failed" << std::endl;
        }
        catch (msgpack::type_error&) {
            std::cout << "type error" << std::endl;
        }
    }
}

ToMultStr, ToWideStrはこちらを参照:
MFC/ATL - std::stringとstd::wstringの相互変換