4

Edit : Hi all !!

I'm currently trying to access to C++ functions from Python and I'm facing to a problem when I try to pass Python list as argument to a function.

here is the C++ function definition I'm trying to access (used to send command to PC/SC reader) :

SRpdu *SendAPDU(unsigned int uiAPDU, //Command
                unsigned int ucLE,   //Data expected for response
                unsigned int ucLC,   //Size of data buffer
                unsigned char * pucDataBuf = 0); //data buffer

My goal is to call this function as following from python like in example below. The goal is to convert the list [1,2,3] to a unsigned char * buffer :

SendAPDU(0x01020304, 0, 3, [1, 2, 3])

Insipired from example "33.9.1 Converting Python list to a char **" from SWIG documentation http://www.swig.org/Doc2.0/Python.html#Python_nn57, I defined following typemap to handle unsigned char * but unfortunately it seems that the typemap is not used. Actually I can use the function only with last argument ignored or set to None.

Python code :

    >>> SendAPDU(0x02000000, 2, 0)  
    [36864, [30, 240]]                  #This call is working
    >>> SendAPDU(0x02000000, 2, 0, None)
    [36864, [30, 240]]                  #Also working

Then if I try to put a list for data of the command (replacing None in previous example), I receive the following error :

>>> SendAPDU(0x02000000, 2, 4, [1, 2, 3, 4]) # HERE IT'S NOT WORKING
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "EMReaderEx.py", line 196, in SendAPDU
        def SendAPDU(self, *args): return _EMReaderEx.EMReaderEx_SendAPDU(self, *args)
    NotImplementedError: Wrong number or type of arguments for overloaded function 'EMReaderEx_SendAPDU'.
      Possible C/C++ prototypes are:
        EMReaderEx::SendAPDU(unsigned int,unsigned int,unsigned int,unsigned char *)
        EMReaderEx::SendAPDU(unsigned int,unsigned int,unsigned int)
        EMReaderEx::SendAPDU(SApdu &)

I think we are here in case of "Wrong type of argument", so I guess that the typemap is not used because I think, but not sure, that the function is not called because of the parameter format doesn't match. So the main question is how can I pass a list and be sure that will be accepted by the function (and therefore catched by the typemap) ?

I think I missed something because I didn't found any working solution for that, and it should relatively used often.

Here is the code of the typemap code in SWIG .i file:

%typemap(in) unsigned char * {
      // Check if is a list 
      unsigned char *ucBuf = NULL;
      if (PyList_Check($input) && PyList_Size($input) > 0) {
        int size = PyList_Size($input);
        int i = 0;
        ucBuf = (unsigned char *) malloc((size+1)*sizeof(unsigned char));
        for (i = 0; i < size; i++) {
          PyObject *o = PyList_GetItem($input,i);
          if (PyLong_Check(o))
            ucBuf[i] = (unsigned char) PyLong_AsLong(o);
          else {
            PyErr_SetString(PyExc_TypeError,"list must contain integers");
            free(ucBuf);
            return NULL;
          }
        }
      } 
      $1 = &ucBuf[0];
    }

    %typemap(freearg) unsigned char * {
        if($1 != NULL)
            free( $1);
    }

In Resume, how to do the SWIG typemap to call C++ function :

SRpdu * SendAPDU(unsigned int uiAPDU, unsigned int ucLE, unsigned int ucLC, unsigned char * pucDataBuf);

Like that from python:

SendAPDU(0x02000000, 2, 4, [1, 2, 3, 4])

Any help is welcome Thanks in advance

p.s. Sorry if my english is bad, it's not my native language.

Gojir4
  • 313
  • 2
  • 17

1 Answers1

1

You should look into module arrays.

In particular, you are looking to call fromlist. If you are using a list to pass instead of a string just because you think that's what you should do, there is a string function available, fromstring. Either way, you can simply initialize the array with format specifier 'B' (notice that capital).

Example usage:

array ('B', [1, 2, 1, 0, 3, 6, 0, 6])
Nathaniel Ford
  • 20,545
  • 20
  • 91
  • 102
David Stone
  • 26,872
  • 14
  • 68
  • 84
  • Hi David, Thanks for your reply. I tried again with an array, but I got the same error again. Or maybe I misunderstood what you meant. `>>> data = array.array('B', [1,2,3,4]) >>> e.SendAPDU(0x13A00000, 0x00, 0x04, data) ` – Gojir4 Aug 09 '11 at 09:40
  • I didn't understand why you said "If you are using a list to pass instead of a string just because you think that's what you should do". Is it better to use string in Python ? Based on this I tried to use a string, and it works ;-). The format is not very friendly but I can live with that. `>>> data = '\x01\x02\x03\x04' >>> e.SendAPDU(0x13A00000, 0x00, 0x04, data) Command passed Status Word : 9000` – Gojir4 Aug 09 '11 at 09:56
  • I still didn't find what I want for now. But I stopped to investigate in this way and I think I will used COM interface instead of wrapping C++ to Python. But anyway any responses is still welcome (also for my commencts above). – Gojir4 Aug 24 '11 at 09:05