gpliu
gpliu

Reputation: 249

C++'s char * by swig got problem in Python 3.0

Our C++ lib works fine with Python2.4 using Swig, returning a C++ char* back to a python str. But this solution hit problem in Python3.0, error is:

Exception=(, UnicodeDecodeError('utf8', b"\xb6\x9d\xa.....",0, 1, 'unexpected code byte')

Our definition is like(working fine in Python 2.4):

void  cGetPubModulus(
 void*  pSslRsa,
    char*  cMod,
    int*   nLen );

%include "cstring.i"
%cstring_output_withsize( char* cMod, int* nLen );

Suspect swig is doing a Bytes->Str conversion automatically. In python2.4 it can be implicit but in Python3.0 it's no long allowed.. Anyone got a good idea? thanks

Upvotes: 1

Views: 2279

Answers (2)

Sebastian
Sebastian

Reputation: 5855

I came across a similar problem. I wrote a SWIG typemap for a custom char array (an unsigned char in fact) and it got SEGFAULT when using Python 3. So I debugged the code within the typemap and I realized the problem Lennart states.

My solution to that problem was doing the following in that typemap:

%typemap(in) byte_t[MAX_FONTFACE_LEN] {
   if (PyString_Check($input))
   {
     $1 = (byte_t *)PyString_AsString($input);
   }
   else if  (PyUnicode_Check($input))
   {
     $1 = (byte_t *)PyUnicode_AsEncodedString($input, "utf-8", "Error ~");
     $1 = (byte_t *)PyBytes_AS_STRING($1);
   }
   else
   {
     PyErr_SetString(PyExc_TypeError,"Expected a string.");
     return NULL;
   }
}   

That is, I check what kind of string object PyObject is. The functions PyString_AsString() and PyUnicode_AsString() will return > 0 if its input it's an UTF- 8 string or an Unicode string respectively. If it's an Unicode string, we convert that string to bytes in the call PyUnicode_AsEncodedString() and later on we convert those bytes to a char * with the call PyBytes_AS_STRING().

Note that I vaguely use the same variable for storing the unicode string and converting it later to bytes. Despite of being that questionable and maybe, it could derive in another coding-style discussion, the fact is that I solved my problem. I have tested it out with python3 and python2.7 binaries without any problems yet.

And lastly, the last line is for replicating an exception in the python call, to inform about that input wasn't a string, either utf nor unicode.

Upvotes: 3

Lennart Regebro
Lennart Regebro

Reputation: 172209

It's rather Python 3 that does that conversion. In Python 2 bytes and str are the same thing, in Python 3 str is unicode, so something somewhere tries to convert it to Unicode with UTF8, but it's not UTF8.

Your Python 3 code needs to return not a Python str, but a Python bytes. This will not work with Python 2, though, so you need preprocessor statements to handle the differences.

Upvotes: 3

Related Questions