Using python 2.7.6 on darwin and windows, both using protoc 2.5.0 and libs 
from 2.5.0, the python code on windows (see test.py in the attached zip) 
contains two extra bytes valued 0x0D in the message compared to the darwin 
version. These extra bytes are preventing c++ libprotobuf from parsing the 
file. Just to be sure it wasn't some null termination causing the parse to 
fail, I'm using ParsePartialFromArray in the exe.
The same code run on darwin using the same version of python (CPython 
2.7.6) and protobufs (2.5.0) generates the correct code and can be parsed 
with the windows and python c++ code. It appears only the python code on 
windows is producing incompatible messages.

Attached is minimal code and setup for reproducing the problem:
Entity.proto (protobuf def)
main.cpp (c++ parsing code)
test.py (python code generating protobuf message)
test_Darwin.pb (the output from the python file on darwin)
test_Windows.pb (the output from the python file on windows)
wscript (simple waf script for building these files)


Any help would be greatly appreciated since this is a major issue for my 
project.
Thanks!
/andrew

-- 
You received this message because you are subscribed to the Google Groups 
"Protocol Buffers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to protobuf+unsubscr...@googlegroups.com.
To post to this group, send email to protobuf@googlegroups.com.
Visit this group at http://groups.google.com/group/protobuf.
For more options, visit https://groups.google.com/groups/opt_out.

Attachment: test_Windows.pb
Description: Binary data

Attachment: Entity.proto
Description: Binary data

#include "Entity.pb.h"

#define ASSERT(condition, message) { if ( !(condition) ) { printf("`" #condition "` failed in %s line %d : `" #message "`\n", __FILE__, __LINE__ ); std::exit(EXIT_FAILURE); } }

char* getFileString(const char* filename, size_t& size)
{
    FILE* pFile = fopen(filename, "rb");
    ASSERT( pFile != NULL, "Error opening file!" );

    fseek (pFile , 0 , SEEK_END);
    size = ftell (pFile);
    rewind (pFile);

    char* buffer = (char*) malloc ( sizeof(char) * size );

    int result = fread( buffer, 1, size, pFile );
    ASSERT( result == size, "Error reading file!" );

    fclose (pFile);
    return buffer;
}

int main(int argc, char **argv)
{
    int res = 0;
    if ( argc < 2 )
    {
        printf("Run with a file to run the test!\n");
        return -1;
    }
    else
    {
        size_t size;
        char* data = getFileString(argv[1], size);

        Entity::Entities entitiesMsg;
        bool res = entitiesMsg.ParsePartialFromArray(data, size);
        if ( res )
        {
            printf("Succeeeded!\n");
        }
        else
        {
            printf("failed!\n");
            return -1;
        }

        const google::protobuf::RepeatedPtrField<Entity::Entity>& entities = entitiesMsg.entities(); 
        for (google::protobuf::RepeatedPtrField<Entity::Entity>::const_iterator entIT = entities.begin(); entIT != entities.end(); ++entIT )
        {
            const Entity::Entity& entityMsg = *entIT;

            unsigned long long entityID = entityMsg.entityid();
            printf("Entity %llu\n", entityID);
        }
    }

    return 0;
}
import sys
import Entity_pb2

def parse_list(values,message):
    '''parse list to protobuf message'''
    if len(values) > 0 and isinstance(values[0],dict):#value needs to be further parsed
        for v in values:
            cmd = message.add()
            parse_dict(v,cmd)
    else:#value can be set
        message.extend(values)


def parse_dict(values,message):
    for k,v in values.iteritems():
        if isinstance(v,dict):#value needs to be further parsed
            parse_dict(v,getattr(message,k))
        elif isinstance(v,list):
            parse_list(v,getattr(message,k))
        else:#value can be set
            try:
                setattr(message, k, v)
            except AttributeError:
                logging.basicConfig()
                l.warning('try to access invalid attributes %r.%r = %r',message,k,v)
                
            

def dict_to_protobuf(value,message):
    parse_dict(value,message)
    return message

def main():
    data = {
        "entities": [
            {
                "entityID": 1,
                "components": [
                    {
                        "name": "ABC",
                        "data": ""
                    }
                ]
            }
        ]
    }

    msg = dict_to_protobuf(data, Entity_pb2.Entities())

    f = open(sys.argv[1], "w")
    f.write(msg.SerializeToString())
    f.close()

try:
    main()
    sys.exit(0)
except:
    sys.exit(-1)

Attachment: test_Darwin.pb
Description: Binary data

import os
import fnmatch
import subprocess
import sys
from contextlib import contextmanager
import copy
import sys

top = '.'
out = 'build'
APPNAME = 'testProtobufs'
VERSION = '0.0'

# For OSX (clang++):
"""
CXX=clang++ ./waf configure
./waf
./waf makeFromPython
./waf runTests
"""

# For windows (MSVC x86):
"""
python waf configure --msvc_targets="x86"
python waf
python waf makeFromPython
python waf runTets
"""

def options(opt):
    opt.load('compiler_cxx')

def LoadLibs(cnf, libDict):
    cnf.env.append_value("LibsToUse", libDict.keys())

    for libUseName, libName in libDict.iteritems():
        cnf.check(compiler='cxx',
                  lib=libName,
                  mandatory=True,
                  uselib_store=libUseName)


def winConfig(cnf):
    cnf.load('compiler_cxx')

    libs = {
        "PROTOBUF": "libprotobuf",
    }

    LoadLibs(cnf, libs)
    cnf.env.append_value('CXXFLAGS', ['/EHsc', '/MT'])
    cnf.env.append_value('LINKFLAGS', [])


def darwinConfig(cnf):
    cnf.load('compiler_cxx')

    libs = {
        "PROTOBUF": "protobuf",
    }
    LoadLibs(cnf, libs)

    baseFlags = ['-stdlib=libstdc++', '-D', 'USE_JEM']
    baseFlags.extend(['-O3'])
    compileFlags = copy.copy(baseFlags)
    compileFlags.extend(['-o'])

    cnf.env.append_value('CXXFLAGS', compileFlags)
    cnf.env.append_value('LINKFLAGS', baseFlags)


CONFIGS = {
    "win32": winConfig,
    "darwin": darwinConfig
}


def configure(cnf):
    CONFIGS[sys.platform](cnf)


def RunAllInDir(directory, extensions, runInDir, excludes=[]):
    excludedList = []
    for root, dirs, files in os.walk(directory):
        for extension in extensions:
            for filename in fnmatch.filter(files, '*.' + extension):
                fullName = os.path.join(root, filename)
                if filename not in excludes:
                    runInDir(fullName)
                else:
                    excludedList.append(fullName)
    return excludedList


@contextmanager
def pushd(newDir):
    previousDir = os.getcwd()
    os.chdir(newDir)
    yield
    os.chdir(previousDir)

def build(bld):
    subprocess.call(["protoc", "--version"])
    protoBufBuild = ["protoc", "--cpp_out=.", "--python_out=.", "Entity.proto"]
    exitCode = subprocess.call(protoBufBuild)
    if exitCode != 0:
        print "Proto buffers build step failed in dir " + dirName
        sys.exit(1)

    libs = bld.env.LibsToUse

    bld.program(features=['cxx'],
        source=["main.cpp", "Entity.pb.cc"],
        includes=["protobufIncludes"],
        target='testProtobufs',
        use=libs,
        )

def makeFromPython(bld):
    subprocess.call(["python", "test.py", "test.pb"])

def runTests(bld):
    if sys.platform == "win32":
        subprocess.call([".\\build\\testProtobufs", "test.pb"])
    else:
        subprocess.call(["./build/testProtobufs", "test.pb"])

Reply via email to