protobuf for lua 實現

先上代碼:


#ifndef _UNIL_H_
#define _UNIL_H_

#include <sstream>
#include <string>
#include<cstring>
#include <iostream>
#include "error.h"

using namespace std;

#define BYTE_LEN 8
#define SHORT_LEN 2
#define PROTO_BIG_ENDIAN
//#define PROTO_LITTLE_ENDIAN

namespace unil{

    typedef signed char         int8;
    typedef short               int16;
    typedef int                 int32;
    typedef long long           int64;

    typedef unsigned char       uint8;
    typedef unsigned short      uint16;
    typedef unsigned int        uint32;
    typedef unsigned long long  uint64;

    union Data
    {
    	int16 shortData;
    	uint8 charData[2];
    };

    inline void Short2Bit(int16 data, uint8 *buf)
    {
    #ifdef LITTLE_ENDIAN
        #ifdef PROTO_LITTLE_ENDIAN
            memcpy(buf, &data, SHORT_LEN);
        #else
            buf[0] = data >> BYTE_LEN;
            buf[1] = data;
        #endif
    #else
        #ifdef PROTO_LITTLE_ENDIAN
            buf[0] = data >> BYTE_LEN;
            buf[1] = data;
        #else
            memcpy(buf, &data, SHORT_LEN);
        #endif
    #endif
    }

	inline int Bit2Short(const uint8* buff, uint32 beg, uint32 len, int16& outLen)
	{
		if(NULL == buff || len < SHORT_LEN)
			return ERROR::ERROR_BIT2SHORT;
		Data d;
    #ifdef LITTLE_ENDIAN
	    #ifdef PROTO_LITTLE_ENDIAN
		    d.charData[0] = buff[beg];
		    d.charData[1] = buff[beg+1];
	    #else
		    d.charData[1] = buff[beg];
		    d.charData[0] = buff[beg+1];
	    #endif
    #else
        #ifdef PROTO_LITTLE_ENDIAN
            d.charData[1] = buff[beg];
            d.charData[0] = buff[beg+1];
        #else
            d.charData[0] = buff[beg];
            d.charData[1] = buff[beg+1];
        #endif
    #endif
		outLen = d.shortData;
		return ERROR::SUCCESS_UNIL;
	}

	inline int String2Int(const string& str)
	{
		int number;
		std::stringstream stream;
		stream << str;
		stream >> number;
		return number; 
	}

    inline string Int2String(uint32 data)
	{
		stringstream ss;
		ss << data; 
		string result = ss.str();
		return result; 
	}
};

#endif 



#ifndef _PROTO_CPP_H_
#define _PROTO_CPP_H_

extern "C"
{
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
}

#include <iostream>
#include <string>
#include "error.h"
#include "unil.h"

using namespace unil;
using namespace std;
using namespace google;
using namespace google::protobuf;

typedef unsigned int uint;
typedef short int sint;

class Proto{

    public:

        static Proto* getInstance();

        ERROR pack(lua_State* L);
        ERROR unpack(lua_State* L);

        bool hasRes(const string& typeName);
        ERROR setProto(const string& packFile,const string& unpackFile);

        ~Proto();

    private:

        ERROR packHeader(int &outType, lua_State* L,uint8 *&packBuf,uint &packBufLen);
        ERROR packContent(int type, lua_State* L, uint8 *&packBuf,uint &packBufLen);
        void pack(Message* message, const FieldDescriptor* pFieldDescriptor, lua_State* L);

        ERROR unpackHeader(const uint8* buff, uint32 length, lua_State* L, int& outType, int& session,int& timestamp);
        ERROR unpackContent(int type, int session, int timestamp,const uint8* buff, uint32 length, lua_State* L);
        void unpack(const Message& message, lua_State* L);

        void getValue(
            const Reflection* reflection,
            const FieldDescriptor* pFieldDescriptor,
            const Message& message,
            lua_State* L,
            int index = 0
            );
        
        void setValue(
            const Reflection* reflection,
            const FieldDescriptor* pFieldDescriptor,
            Message *message,
            lua_State* L
            );

        void merage(uint8* des, uint8* src, uint beg, uint len);
        const void* getBuffer(lua_State *L, int index, size_t *sz);

        static Proto* instance;

        string unpackProtoFileName;
        string packProtoFileName;
        const string headerProtoFileName;

    private:
        explicit Proto();
        Proto(const Proto&){}
};


#endif

#include "pb.h"
#include "error.h"
#include <google/protobuf/dynamic_message.h>

#include <iostream>
#include <iomanip>
 
Proto* Proto::instance = nullptr;

Proto::Proto():
    headerProtoFileName("protohead.proto")
{
}

Proto* Proto::getInstance()
{
    if(nullptr == instance)
    {
        instance = new Proto();
    }
    return instance;
}

Proto::~Proto()
{
}

void Proto::merage(uint8* des, uint8* src, uint beg, uint len)
{
    if(nullptr == des || nullptr == src)
        return;
    for(uint i = 0;i < len; ++i)
        des[beg+i] = src[i];
}

ERROR Proto::setProto(const string& packFile,const string& unpackFile)
{
    packProtoFileName = packFile;
    unpackProtoFileName = unpackFile;

    const FileDescriptor *packfileDescriptor = DescriptorPool::generated_pool()->FindFileByName(packProtoFileName);
    if(nullptr == packfileDescriptor)
    {
        return ERROR::ERROR_PACK_FILE;
    }
    const FileDescriptor *unpackfileDescriptor = DescriptorPool::generated_pool()->FindFileByName(unpackProtoFileName);
    if(nullptr == unpackfileDescriptor)
    {
        return ERROR::ERROR_UNPACK_FILE;
    }
    return ERROR_NONE;
}

ERROR Proto::pack(lua_State* L)
{
    ERROR error = ERROR::SUCCESS_PACK;
    
    int type = -1;
    uint8* headerBuf = nullptr;
    uint headerBufLen = 0;
    error = packHeader(type, L, headerBuf, headerBufLen);

    if(ERROR::SUCCESS_PACK != error)
    {
        return error;
    }
    
    uint8* contentBuf = nullptr;
    uint contentBufLen = 0;

    error = packContent(type, L, contentBuf, contentBufLen);


    if(ERROR::SUCCESS_PACK != error)
    {    
        return error;
    }

    uint8 headerLenBuf[HEADER_LEN] = {0};
    uint8 contentLenBuf[CONTENT_LEN] = {0};
    Short2Bit(headerBufLen, headerLenBuf);
    Short2Bit(contentBufLen, contentLenBuf);

    uint totalBufLen = headerBufLen + contentBufLen + HEADER_LEN + CONTENT_LEN;
    uint8 *packBuf = new uint8 [totalBufLen];

    merage(packBuf,headerLenBuf,0,HEADER_LEN);
    merage(packBuf,headerBuf, HEADER_LEN, headerBufLen);
    merage(packBuf,contentLenBuf, HEADER_LEN + headerBufLen, CONTENT_LEN);
    merage(packBuf,contentBuf, HEADER_LEN + CONTENT_LEN + headerBufLen, contentBufLen);

    lua_settop(L,0);
    lua_pushlstring(L, (const char *)packBuf, totalBufLen);

    delete []headerBuf;
    delete []contentBuf;
    delete []packBuf;
    return error;
}   
 
ERROR Proto::packHeader(int &outType, lua_State* L ,uint8* &packBuf,uint &packBufLen)
{
    packBuf = nullptr;
    packBufLen = 0;
    int session = 0;
    int timestamp = 0;
    string typeName = "";
    int depth = lua_gettop(L);


    if(4 == depth)
    {
        if(lua_type(L, -1) == LUA_TNUMBER)
        {
            session = luaL_checkinteger(L, -1);
        }
        else if(lua_type(L, -1) == LUA_TSTRING)
        {
            string s = luaL_checkstring(L, -1);
            session = String2Int(s); 
        }

        lua_pop(L, 1);

        if(lua_type(L, -1) == LUA_TNUMBER)
        {
            timestamp = luaL_checkinteger(L, -1);
        }
        else if(lua_type(L, -1) == LUA_TSTRING)
        {
            string s = luaL_checkstring(L, -1);
            timestamp = String2Int(s); 
        }
        lua_pop(L,1);
    }
    else if(3 == depth)
    {
        if(lua_type(L, -1) == LUA_TNUMBER)
        {
            timestamp = luaL_checkinteger(L, -1);
        }
        else if(lua_type(L, -1) == LUA_TSTRING)
        {
            string s = luaL_checkstring(L, -1);
            timestamp = String2Int(s); 
        }
        lua_pop(L,1);
    }
    else if(2 == depth)
    {
        ;
    }
    else
    {
        return ERROR::ERROR_ARGS; 
    }

    if(lua_type(L, 1) == LUA_TSTRING)
        typeName = luaL_checkstring(L, 1);

    if(typeName.compare("") == 0)
        return ERROR::ERROR_PACK_TYPE_NAME;

    const FileDescriptor *fileDescriptor = DescriptorPool::generated_pool()->FindFileByName(packProtoFileName);
    if(nullptr == fileDescriptor)
    {
        return ERROR::ERROR_PACK_FILE;
    }

    const Descriptor *descriptor = fileDescriptor->FindMessageTypeByName(typeName);
    if(nullptr == descriptor)
    {
        return ERROR::ERROR_PACK_TYPE_NAME;
    }

    outType = descriptor->index();

//靜態設置了協議頭,代碼略

    packBufLen  = header.ByteSize();
    packBuf = new uint8[packBufLen];

    if(!header.SerializeToArray(packBuf, packBufLen))
    {
        delete []packBuf;
        packBufLen = 0;                
        return ERROR_PACK_ERROR;
    }
    return ERROR::SUCCESS_PACK;
}

ERROR Proto::packContent(int type, lua_State* L, uint8* &packBuf, uint &packBufLen)
{
    packBuf = nullptr;
    packBufLen = 0;

    const FileDescriptor *fileDescriptor = DescriptorPool::generated_pool()->FindFileByName(packProtoFileName);
    if(nullptr == fileDescriptor)
    {
        return ERROR::ERROR_PACK_FILE;
    }
    if(type >= fileDescriptor->message_type_count() || type < 0)
    {
        return ERROR::ERROR_PACK_TYPE_INDEX;
    }
    const Descriptor *descriptor = fileDescriptor->message_type(type);
    if(nullptr == descriptor)
    {
        return ERROR::ERROR_PACK_TYPE_INDEX;
    }
    
    DynamicMessageFactory factory;
    const Message *msg = factory.GetPrototype(descriptor);
    Message *message = msg->New();

    pack(message, nullptr, L);

    packBufLen = message->ByteSize();
    packBuf = new uint8[packBufLen];
    
    if(!message->SerializeToArray(packBuf, packBufLen))
    {
        packBufLen = 0;
        delete []packBuf;
        return ERROR::ERROR_PACK_ERROR;
    }

    delete message;
    return ERROR::SUCCESS_PACK;
}

void Proto::setValue(
    const Reflection* reflection,
    const FieldDescriptor* pFieldDescriptor,
    Message *message,
    lua_State* L)
{  
    switch (pFieldDescriptor->cpp_type())
    {
        case FieldDescriptor::CPPTYPE_STRING:
        {
            if(lua_type(L, -1) == LUA_TSTRING)
            {
                size_t len = 0;
                const char* c = luaL_checklstring(L,-1,&len);
                std::string str(c,len); 
                reflection->SetString(message, pFieldDescriptor, str);
            }
            break;
        }
        case FieldDescriptor::CPPTYPE_INT32:
        {
            if(lua_type(L, -1) == LUA_TNUMBER)
            {
                reflection->SetInt32(message, pFieldDescriptor, luaL_checkinteger(L, -1));
            }
            else if(lua_type(L, -1) == LUA_TSTRING)
            { 
                string s = luaL_checkstring(L, -1);
                int value = String2Int(s);
                reflection->SetInt32(message, pFieldDescriptor, value);
            }
            break;
        }
        case FieldDescriptor::CPPTYPE_UINT32:
        {
            if(lua_type(L, -1) == LUA_TNUMBER || lua_type(L, -1) == LUA_TSTRING)
            {
                reflection->SetUInt32(message, pFieldDescriptor, luaL_checkinteger(L, -1));
            }
            break;
        }
        case FieldDescriptor::CPPTYPE_BOOL:
        {
            if(lua_type(L, -1) == LUA_TBOOLEAN )
            {
                reflection->SetBool(message, pFieldDescriptor, luaL_checkinteger(L, -1));
            }
            break;
        }
        case FieldDescriptor::CPPTYPE_INT64:
        {
            if(lua_type(L, -1) == LUA_TNUMBER)
            {
                reflection->SetInt64(message, pFieldDescriptor, luaL_checkinteger(L, -1));
            }
            break;
        }
        case FieldDescriptor::CPPTYPE_UINT64:
        {
            if(lua_type(L, -1) == LUA_TNUMBER)
            {
                reflection->SetUInt64(message, pFieldDescriptor, luaL_checkinteger(L, -1));
            }
            break;
        }
        case FieldDescriptor::CPPTYPE_ENUM:
        {
            //if(lua_type(L, -1) == LUA_TNUMBER)
            //{
            //    reflection->SetEnum(message, pFieldDescriptor, luaL_checkinteger(L, -1));
            //}
            break;
        }
        case FieldDescriptor::CPPTYPE_DOUBLE:
        {
            if(lua_type(L, -1) == LUA_TNUMBER)
            {
                reflection->SetDouble(message, pFieldDescriptor, luaL_checknumber(L, -1));
            }
            break;
        }
        case FieldDescriptor::CPPTYPE_FLOAT:
        {
            if(lua_type(L, -1) == LUA_TNUMBER){
                reflection->SetFloat(message, pFieldDescriptor, luaL_checknumber(L, -1));
            }
            break;
        }
        case FieldDescriptor::CPPTYPE_MESSAGE:
        {
            if(lua_type(L, -1) == LUA_TTABLE){
                Message* subMessage = reflection->MutableMessage(message, pFieldDescriptor);
                pack(subMessage, nullptr, L);
            }
            break;
        }
        default:
        {
            //log
            break;
        }
    }
}

void Proto::pack(Message* message, const FieldDescriptor* pFieldDescriptor, lua_State* L)
{
    int it = lua_gettop(L);
    if(1 == lua_isnil(L,it))
    {
        lua_pop(L, 1);
        return;
    }
    lua_pushnil(L);

    const Reflection* reflection = message->GetReflection();
    const Descriptor* descriptor = message->GetDescriptor();

    while(0 != lua_next(L, it))
    {
        if(LUA_TNUMBER == lua_type(L, -2))
        {
            if(nullptr != pFieldDescriptor && pFieldDescriptor->is_repeated())
            {
                if(lua_type(L, -1) == LUA_TTABLE)
                {
                    Message* subMessage = reflection->AddMessage(message, pFieldDescriptor);
                    pack(subMessage, nullptr, L);
                }
                else if(lua_type(L ,-1) == LUA_TSTRING)
                {
                    size_t len = 0;
                    const char* c = luaL_checklstring(L,-1,&len);
                    std::string str(c,len); 
                    reflection->AddString(message, pFieldDescriptor, str);
                }
                else if(lua_type(L, -1) == LUA_TNUMBER)
                {
                    if(pFieldDescriptor->cpp_type() ==  FieldDescriptor::CPPTYPE_INT32)
                    {
                        int value = luaL_checkinteger(L,-1);
                        reflection->AddInt32(message,  pFieldDescriptor, value);
                    }
                    else if(pFieldDescriptor->cpp_type() ==  FieldDescriptor::CPPTYPE_INT64)
                    {   
                        int64 value = luaL_checkinteger(L,-1);
                        reflection->AddInt64(message,  pFieldDescriptor, value);
                    }
                    else if(pFieldDescriptor->cpp_type() ==  FieldDescriptor::CPPTYPE_UINT32)
                    {   
                        uint32 value = luaL_checkinteger(L,-1);
                        reflection->AddInt32(message,  pFieldDescriptor, value);
                    }
                    else if(pFieldDescriptor->cpp_type() ==  FieldDescriptor::CPPTYPE_UINT64)
                    {   
                        uint64 value = luaL_checkinteger(L,-1);
                        reflection->AddUInt64(message,  pFieldDescriptor, value);
                    }
                    else if(pFieldDescriptor->cpp_type() ==  FieldDescriptor::CPPTYPE_BOOL)
                    {   
                        bool value = luaL_checkinteger(L,-1);
                        reflection->AddBool(message,  pFieldDescriptor, value);
                    }
                    else if(pFieldDescriptor->cpp_type() ==  FieldDescriptor::CPPTYPE_FLOAT)
                    {   
                        float value = luaL_checknumber(L,-1);
                        reflection->AddFloat(message,  pFieldDescriptor, value);
                    }
                    else if(pFieldDescriptor->cpp_type() ==  FieldDescriptor::CPPTYPE_DOUBLE)
                    {   
                        double value = luaL_checknumber(L,-1);
                        reflection->AddDouble(message,  pFieldDescriptor, value);
                    }
                    else
                    {
                        //log
                    }
                }
           }        
        }    
        else
        {
            string fieldName = luaL_checkstring(L, -2);
            const FieldDescriptor* fieldDescriptor = descriptor->FindFieldByName(fieldName);
            if(fieldDescriptor)
            {
                if(fieldDescriptor->is_repeated())
                {
                    pack(message, fieldDescriptor, L);
                }
                else
                {
                    setValue(reflection, fieldDescriptor, message, L);
                }
            }
        }
        lua_pop(L, 1);
    }
}

const void *Proto::getBuffer(lua_State *L, int index, size_t *sz) {
    const void * buffer = nullptr;
    int t = lua_type(L, index);
    if (t == LUA_TSTRING) 
    {
        buffer = lua_tolstring(L, index, sz);
    } else 
    {
        if (t != LUA_TUSERDATA && t != LUA_TLIGHTUSERDATA) 
        {
            luaL_argerror(L, index, "Need a string or userdata");
            return nullptr;
        }
        buffer = lua_touserdata(L, index);
        *sz = luaL_checkinteger(L, index+1);
    }
    return buffer;
}

ERROR Proto::unpack(lua_State* L)
{
    size_t len = 0;
    const uint8 * buff = (const uint8*)getBuffer(L, 1, &len);

    ERROR error = ERROR::SUCCESS_UNPACK;
    if(len < HEADER_LEN)
        return ERROR::ERROR_UNPACK_LEN1;

    sint headerLen = 0;
    Bit2Short(buff, 0, HEADER_LEN, headerLen);
    int type = -1;
    int session = -1;
    int timestamp = 0;

    if(len < headerLen + HEADER_LEN)
        return ERROR::ERROR_UNPACK_LEN2;

    error = unpackHeader(
        buff + HEADER_LEN, 
        headerLen, 
        L, 
        type, 
        session,    
        timestamp
        );
    
    if(ERROR::SUCCESS_UNPACK != error) 
    {
        std::cout<<"HEX DATA ALL :"<<std::endl;
        for(int i = 0; i<len; i++) {
            std::cout.fill('0');//設置填充字符
            std::cout.width(2);//設置域寬
            std::cout<<std::hex<<(int)buff[i];
        }
        std::cout<<std::endl;
        
        return error; 
    }

    if(len < HEADER_LEN + headerLen + CONTENT_LEN)
        return ERROR::ERROR_UNPACK_LEN3;

    sint contentLen = 0;
    Bit2Short(
        buff,
        HEADER_LEN + headerLen,
        CONTENT_LEN,
        contentLen
    );

    if(len < headerLen + contentLen + HEADER_LEN + CONTENT_LEN)
    {
        return ERROR::ERROR_UNPACK_LEN4;
    }    
    error = unpackContent(
        type,
        session,
        timestamp,
        buff + HEADER_LEN + headerLen + CONTENT_LEN,
        contentLen,
        L
        );

    return error;
}


void Proto::unpack(const Message& message,lua_State* L)
{  
    const Reflection* reflection = message.GetReflection();
    const Descriptor* descriptor = message.GetDescriptor();

    for (int i = 0; i < descriptor->field_count(); ++i)
    {
        const FieldDescriptor* pFieldDescriptor = descriptor->field(i);
        if(pFieldDescriptor->is_repeated())
        {
            if(pFieldDescriptor->cpp_type() ==  FieldDescriptor::CPPTYPE_MESSAGE)
            {
                const RepeatedPtrField<Message>& pRepeatedField = reflection->GetRepeatedPtrField<Message>(message,pFieldDescriptor);
                string fieldName = pFieldDescriptor->name();
                lua_pushstring(L,fieldName.c_str());
                lua_newtable(L);
                for(int i = 0;i < pRepeatedField.size();++i)
                {
                    lua_pushnumber(L, i+1);
                    lua_newtable(L);
                    const Message& subMessage = reflection->GetRepeatedMessage(message, pFieldDescriptor, i);
                    unpack(subMessage,L);
                    lua_settable(L,-3);
                }

                lua_settable(L, -3);
            }
            else
            {
                if(pFieldDescriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING)
                {
                    const RepeatedPtrField<string>& pRepeatedField = reflection->GetRepeatedPtrField<string>(message,pFieldDescriptor);
                    string fieldName = pFieldDescriptor->name();
                    lua_pushstring(L,fieldName.c_str());
                    lua_newtable(L);
                    for(int i = 0;i < pRepeatedField.size();++i)
                    {
                        lua_pushnumber(L, i);
                        const string& str = reflection->GetRepeatedString(message, pFieldDescriptor, i);
                        lua_pushlstring(L, str.c_str(),str.size());
                        lua_settable(L, -3);
                    }
                    lua_settable(L, -3);
                }
                if(pFieldDescriptor->cpp_type() == FieldDescriptor::CPPTYPE_INT32)
                {
                    int psize = reflection->FieldSize(message, pFieldDescriptor);   
                    string fieldName = pFieldDescriptor->name();
                    lua_pushstring(L,fieldName.c_str());
                    lua_newtable(L);
                    for(int i = 0;i < psize;++i)
                    {
                        lua_pushnumber(L, i);
                        int value = reflection->GetRepeatedInt32(message, pFieldDescriptor, i);
                        lua_pushinteger(L, value);
                        lua_settable(L, -3);
                    }
                    lua_settable(L, -3);
                }

                if(pFieldDescriptor->cpp_type() == FieldDescriptor::CPPTYPE_INT64)
                {
                    int psize = reflection->FieldSize(message, pFieldDescriptor);   
                    string fieldName = pFieldDescriptor->name();
                    lua_pushstring(L,fieldName.c_str());
                    lua_newtable(L);
                    for(int i = 0;i < psize;++i)
                    {
                        lua_pushnumber(L, i);
                        int64 value = reflection->GetRepeatedInt64(message, pFieldDescriptor, i);
                        lua_pushinteger(L, value);
                        lua_settable(L, -3);
                    }
                    lua_settable(L, -3);
                }


                if(pFieldDescriptor->cpp_type() == FieldDescriptor::CPPTYPE_BOOL)
                {
                    int psize = reflection->FieldSize(message, pFieldDescriptor);   
                    string fieldName = pFieldDescriptor->name();
                    lua_pushstring(L,fieldName.c_str());
                    lua_newtable(L);
                    for(int i = 0;i < psize;++i)
                    {
                        lua_pushnumber(L, i);
                        int value = reflection->GetRepeatedBool(message, pFieldDescriptor, i);
                        lua_pushinteger(L, value);
                        lua_settable(L, -3);
                    }
                    lua_settable(L, -3);
                }


                if(pFieldDescriptor->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT)
                {
                    int psize = reflection->FieldSize(message, pFieldDescriptor);   
                    string fieldName = pFieldDescriptor->name();
                    lua_pushstring(L,fieldName.c_str());
                    lua_newtable(L);
                    for(int i = 0;i < psize;++i)
                    {
                        lua_pushnumber(L, i);
                        float value = reflection->GetRepeatedFloat(message, pFieldDescriptor, i);
                        lua_pushnumber(L, value);
                        lua_settable(L, -3);
                    }
                    lua_settable(L, -3);
                }


                if(pFieldDescriptor->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE)
                {
                    int psize = reflection->FieldSize(message, pFieldDescriptor);   
                    string fieldName = pFieldDescriptor->name();
                    lua_pushstring(L,fieldName.c_str());
                    lua_newtable(L);
                    for(int i = 0;i < psize;++i)
                    {
                        lua_pushnumber(L, i);
                        double value = reflection->GetRepeatedDouble(message, pFieldDescriptor, i);
                        lua_pushnumber(L, value);
                        lua_settable(L, -3);
                    }
                    lua_settable(L, -3);
                }

                if(pFieldDescriptor->cpp_type() == FieldDescriptor::CPPTYPE_UINT32)
                {
                    int psize = reflection->FieldSize(message, pFieldDescriptor);   
                    string fieldName = pFieldDescriptor->name();
                    lua_pushstring(L,fieldName.c_str());
                    lua_newtable(L);
                    for(int i = 0;i < psize;++i)
                    {
                        lua_pushnumber(L, i);
                        uint32 value = reflection->GetRepeatedUInt32(message, pFieldDescriptor, i);
                        lua_pushinteger(L, value);
                        lua_settable(L, -3);
                    }
                    lua_settable(L, -3);
                }

                if(pFieldDescriptor->cpp_type() == FieldDescriptor::CPPTYPE_UINT64)
                {
                    int psize = reflection->FieldSize(message, pFieldDescriptor);   
                    string fieldName = pFieldDescriptor->name();
                    lua_pushstring(L,fieldName.c_str());
                    lua_newtable(L);
                    for(int i = 0;i < psize;++i)
                    {
                        lua_pushnumber(L, i);
                        uint64 value = reflection->GetRepeatedUInt64(message, pFieldDescriptor, i);
                        lua_pushinteger(L, value);
                        lua_settable(L, -3);
                    }
                    lua_settable(L, -3);
                }
            }
        }
        else
        {
            //
            //if(!reflection->HasField(message, pFieldDescriptor))
            //{
            //    continue;
            //}

            getValue(reflection,pFieldDescriptor,message,L);
        }
    }
}

ERROR Proto::unpackHeader(const uint8* buff,uint32 length,lua_State* L,int &outType,int &session,int ×tamp)
{
//靜態解析協議頭,代碼略

    return ERROR::SUCCESS_UNPACK;
}

ERROR Proto::unpackContent(int type, int session, int timestamp, const uint8* buff, uint32 length, lua_State* L)
{ 
    const FileDescriptor *fileDescriptor = DescriptorPool::generated_pool()->FindFileByName(unpackProtoFileName);
    if(nullptr == fileDescriptor)
    {
        return ERROR::ERROR_UNPACK_FILE;
    }
    
    if(type >= fileDescriptor->message_type_count() || type < 0)
    {
        return ERROR::ERROR_UNPACK_TYPE_INDEX;
    }
    
    const Descriptor *descriptor = fileDescriptor->message_type(type);
    if(nullptr == descriptor)
    {
        return ERROR::ERROR_UNPACK_TYPE_INDEX;
    }

    DynamicMessageFactory factory;
    const Message *msg = factory.GetPrototype(descriptor); 
    Message *message = msg->New(); 

    if (!message->ParseFromArray(buff,length))
    {
        std::cout<<"HEX DATA CONTENT:"<<std::endl;
        for(int i = 0; i<length; i++) {
            std::cout.fill('0');//設置填充字符
            std::cout.width(2);//設置域寬
            std::cout<<std::setbase(16);
            std::cout<<std::hex<<(int)buff[i];
        }
        std::cout<<std::endl;
        return ERROR::ERROR_UNPACK_ERROR;
    }
    lua_settop(L,0);
    lua_pushstring(L,descriptor->name().c_str());
    lua_newtable(L);
    
    unpack(*message,L);

    lua_pushinteger(L,timestamp);
    lua_pushinteger(L,session);

    delete message;
    return ERROR::SUCCESS_UNPACK;
}

void Proto::getValue(
    const Reflection* reflection,
    const FieldDescriptor* pFieldDescriptor,
    const Message &message,
    lua_State* L,
    int index)
{
    if(!pFieldDescriptor->is_repeated())
    {
        string fieldName = pFieldDescriptor->name();
        lua_pushstring(L,fieldName.c_str());
    }
    else
    {
        lua_pushnumber(L,index);
    }

    switch (pFieldDescriptor->cpp_type())
    {
        case FieldDescriptor::CPPTYPE_STRING:
        {
            string value = reflection->GetString(message,pFieldDescriptor);
            lua_pushlstring(L,value.c_str(),value.size());
            break;
        }        
        case FieldDescriptor::CPPTYPE_INT32:
        {
            int32 value = reflection->GetInt32(message,pFieldDescriptor);
            lua_pushinteger(L,value);
            break;
        }
        case FieldDescriptor::CPPTYPE_BOOL:
        {
            int value = reflection->GetBool(message,pFieldDescriptor);
            lua_pushinteger(L,value); 
            break;
        }
        case FieldDescriptor::CPPTYPE_ENUM:
        {
            //int value = reflection->GetEnum(message,pFieldDescriptor);
            //lua_pushinteger(L,value); 
            break;
        }
        case FieldDescriptor::CPPTYPE_FLOAT:
        {
            float value = reflection->GetFloat(message,pFieldDescriptor);
            lua_pushnumber(L,value); 
            break;
        }
        case FieldDescriptor::CPPTYPE_DOUBLE:
        {
            double value = reflection->GetDouble(message,pFieldDescriptor);
            lua_pushnumber(L,value); 
            break;
        }
        case FieldDescriptor::CPPTYPE_UINT64:
        {
            uint64 value = reflection->GetUInt64(message,pFieldDescriptor);
            lua_pushinteger(L,value); 
            break;
        }
        case FieldDescriptor::CPPTYPE_INT64:
        {
            int64 value = reflection->GetInt64(message,pFieldDescriptor);
            lua_pushinteger(L,value); 
            break;
        }
        case FieldDescriptor::CPPTYPE_UINT32:
        {
            uint32 value = reflection->GetUInt32(message,pFieldDescriptor);
            lua_pushinteger(L,value); 
            break;
        }
        case FieldDescriptor::CPPTYPE_MESSAGE:
        {
            lua_newtable(L);
            const Message &subMessage = reflection->GetMessage(message,pFieldDescriptor);
            unpack(subMessage,L);
            break;
        }
        default:
        {
            //log
            break;
        }
    }
    lua_settable(L,-3);
}

bool Proto::hasRes(const string& typeName)
{
    const FileDescriptor *fileDescriptor = DescriptorPool::generated_pool()->FindFileByName(packProtoFileName);
    if(nullptr == fileDescriptor)
    {
           return false;
    }
    const Descriptor *descriptor = fileDescriptor->FindMessageTypeByName(typeName);
    if(nullptr == descriptor)
    {
        return false;
    }
    return true;
}


#include "pb.h"
#include "error.h"

extern "C"{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

extern"C"
int lpack(lua_State *L)
{
	Proto *proto = Proto::getInstance();
    ERROR error = proto->pack(L);
    if(ERROR::SUCCESS_PACK != error)
    {
        return luaL_error(L,"error: %d",error);
    }
    return 1;
}  

extern"C"
int lunpack(lua_State *L)
{
    Proto *proto = Proto::getInstance();
    ERROR error = proto->unpack(L);
    if(ERROR::SUCCESS_UNPACK != error){
        return luaL_error(L, "unpack error: %d",error);
    }
    return lua_gettop(L);
}

extern "C"
int lclear(lua_State *L)
{
    lua_settop(L,0);
    return 0;
}

extern "C"
int lhasres(lua_State *L)
{
    Proto *proto = Proto::getInstance();
    bool hasRes = false;
    if(LUA_TSTRING == lua_type(L, -1))
    {    
        string typeName = lua_tostring(L, -1);
        hasRes = proto->hasRes(typeName);
        lua_settop(L,0);
    }
    lua_pushboolean(L,hasRes);
    return 1;
}

extern "C"
int lsetproto(lua_State *L)
{
    string packFile,unpackFile = "";
    if(LUA_TSTRING == lua_type(L, -1))
    {
        unpackFile = lua_tostring(L,-1);
    }
    if(LUA_TSTRING == lua_type(L, -2))
    {
        packFile =lua_tostring(L,-2);
    }

    Proto *proto = Proto::getInstance();
    ERROR error = proto->setProto(packFile,unpackFile);

    if(ERROR::ERROR_NONE != error)
    {
        return luaL_error(L,"setproto error :%d",error);
    }
    lua_settop(L, 0);
    return 0;
}

extern "C"
int luaopen_protobufclua(lua_State* L) 
{
    luaL_Reg protobufclua[] = {
        {"pack", lpack},
        {"unpack", lunpack},
        {"clear", lclear},
        {"hasRes",lhasres},
        {"setproto",lsetproto},
        {NULL, NULL}
    };

  luaL_newlib(L, protobufclua);

  return 1;
}





protobuf for lua
代碼裏面包含了C++反射處理protobuf,C++構造Lua表,C++讀取Lua表,C++靜態處理protobuf。

大端,小端的short轉換爲字節。

經過測試,代碼穩定。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章