Question

I'm wrapping a C library using Swig to be able to use it in PHP. The library uses u_char * instead of unsigned char *. Swig treats the u_char as a structure that it doesn't know about.

This results in the generated code doing a check to for the argument type, which obviously fails when I pass in a string as char * data.

How do I tell Swig to that u_char pointers are just unsigned char pointers?

i.e. this C function

int c_library_function(u_char *data, size_t data_size);

has this check inside of the generated code:

if(SWIG_ConvertPtr(*args[0], (void **) &arg1, SWIGTYPE_p_unsigned_char, 0) < 0) {
  SWIG_PHP_Error(E_ERROR, "Type error in argument 1 of c_library_function. Expected SWIGTYPE_p_unsigned_char");
}

Which is where it fails.

I've tried adding %typemap(ctype) u_char "unsigned char" to the Swig template, and it seems to have no effect.

Edit To clarify one thing, the u_char is definitely a unsigned char. The C files in the library are including sys/types.h which includes bits/types.h which has the entry:

typedef unsigned char __u_char;

Also, just writing a function to wrap the call to C function, to be able to cast the type, works as expected:

void libraryFunction(u_char *foo) {
    //Does stuff with foo
}

void castLibraryFunction(char *foo) {
     libraryFunction((u_char *)foo);
}

But I don't want to have to write a wrapper for every function that expects a u_char* parameter.

Even more obviously, the type that Swig is checking for is SWIGTYPE_p_unsigned_char i.e. it's understood that the data type is 'unsigned char' but not using an 'unsigned char' pointer, but instead a pointer to a custom structure.

Was it helpful?

Solution

According to Is u_char a standard?, u_char is equivalent to uint8_t (C99), not unsigned char. Hence if you have an array of unsigned char that you receive from PHP, you will have to copy the chars into a new array of uint8_t (u_char), call your lib's C function, and if it mods the data (since it takes a u_char* not a const uchar*) you have to copy the result into the original array so PHP sees the change. If PHP uses immutable strings, you will have to return the string instead.

SWIG can help with some of the above tasks (like via %inline and %extend; I don't think you need type maps).

If u_char really is an unsigned char, and PHP is giving you a char*, then the principle is the same, but you don't need the copy parts, because the size type is the same as char*. You could use %inline:

%inline %{
    int c_library_function(char* phpString, size_t stringSize) {
          return c_library_function((u_char*) phpString, stringSize);
    }
%}

If you don't want to have to do this for every function that expects u_char*, I think your only option is a typemap entry in the .i file, such as

%array_class(unsigned char, char); 

or

%apply char*  {unsigned char*};

but I have never used these.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top