Ejemplo n.º 1
0
void
rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount, NativeType* paramTypes,
                      FFIStorage* paramStorage, void** ffiValues,
                      VALUE* callbackParameters, int callbackCount, VALUE enums)
{
    VALUE callbackProc = Qnil;
    FFIStorage* param = &paramStorage[0];
    int i, argidx, cbidx, argCount;

    if (paramCount != -1 && paramCount != argc) {
        if (argc == (paramCount - 1) && callbackCount == 1 && rb_block_given_p()) {
            callbackProc = rb_block_proc();
        } else {
            rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, paramCount);
        }
    }

    argCount = paramCount != -1 ? paramCount : argc;

    for (i = 0, argidx = 0, cbidx = 0; i < argCount; ++i) {
        int type = argidx < argc ? TYPE(argv[argidx]) : T_NONE;
        ffiValues[i] = param;

        switch (paramTypes[i]) {

        case NATIVE_INT8:
            param->s8 = getSignedInt(argv[argidx++], type, -128, 127, "char", Qnil);
            ADJ(param, INT8);
            break;


        case NATIVE_INT16:
            param->s16 = getSignedInt(argv[argidx++], type, -0x8000, 0x7fff, "short", Qnil);
            ADJ(param, INT16);
            break;


        case NATIVE_INT32:
        case NATIVE_ENUM:
            param->s32 = getSignedInt(argv[argidx++], type, -0x80000000, 0x7fffffff, "int", enums);
            ADJ(param, INT32);
            break;


        case NATIVE_BOOL:
            if (type != T_TRUE && type != T_FALSE) {
                rb_raise(rb_eTypeError, "wrong argument type  (expected a boolean parameter)");
            }
            param->s8 = argv[argidx++] == Qtrue;
            ADJ(param, INT8);
            break;


        case NATIVE_UINT8:
            param->u8 = getUnsignedInt(argv[argidx++], type, 0xff, "unsigned char");
            ADJ(param, INT8);
            break;


        case NATIVE_UINT16:
            param->u16 = getUnsignedInt(argv[argidx++], type, 0xffff, "unsigned short");
            ADJ(param, INT16);
            break;


        case NATIVE_UINT32:
            /* Special handling/checking for unsigned 32 bit integers */
            param->u32 = getUnsignedInt32(argv[argidx++], type);
            ADJ(param, INT32);
            break;


        case NATIVE_INT64:
            if (type != T_FIXNUM && type != T_BIGNUM) {
                rb_raise(rb_eTypeError, "Expected an Integer parameter");
            }
            param->i64 = NUM2LL(argv[argidx]);
            ADJ(param, INT64);
            ++argidx;
            break;


        case NATIVE_UINT64:
            if (type != T_FIXNUM && type != T_BIGNUM) {
                rb_raise(rb_eTypeError, "Expected an Integer parameter");
            }
            param->u64 = NUM2ULL(argv[argidx]);
            ADJ(param, INT64);
            ++argidx;
            break;

        case NATIVE_LONG:
            *(ffi_sarg *) param = NUM2LONG(argv[argidx]);
            ADJ(param, LONG);
            ++argidx;
            break;

        case NATIVE_ULONG:
            *(ffi_arg *) param = NUM2ULONG(argv[argidx]);
            ADJ(param, LONG);
            ++argidx;
            break;

        case NATIVE_FLOAT32:
            if (type != T_FLOAT && type != T_FIXNUM) {
                rb_raise(rb_eTypeError, "Expected a Float parameter");
            }
            param->f32 = (float) NUM2DBL(argv[argidx]);
            ADJ(param, FLOAT32);
            ++argidx;
            break;

        case NATIVE_FLOAT64:
            if (type != T_FLOAT && type != T_FIXNUM) {
                rb_raise(rb_eTypeError, "Expected a Float parameter");
            }
            param->f64 = NUM2DBL(argv[argidx]);
            ADJ(param, FLOAT64);
            ++argidx;
            break;


        case NATIVE_STRING:
            param->ptr = getString(argv[argidx++], type);
            ADJ(param, ADDRESS);
            break;

        case NATIVE_POINTER:
        case NATIVE_BUFFER_IN:
        case NATIVE_BUFFER_OUT:
        case NATIVE_BUFFER_INOUT:
            param->ptr = getPointer(argv[argidx++], type);
            ADJ(param, ADDRESS);
            break;


        case NATIVE_FUNCTION:
        case NATIVE_CALLBACK:
            if (callbackProc != Qnil) {
                param->ptr = callback_param(callbackProc, callbackParameters[cbidx++]);
            } else {
                param->ptr = callback_param(argv[argidx], callbackParameters[cbidx++]);
                ++argidx;
            }
            ADJ(param, ADDRESS);
            break;

        case NATIVE_STRUCT:
            ffiValues[i] = getPointer(argv[argidx++], type);
            break;

        default:
            rb_raise(rb_eArgError, "Invalid parameter type: %d", paramTypes[i]);
        }
    }
}
Ejemplo n.º 2
0
void
rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount, Type** paramTypes,
        FFIStorage* paramStorage, void** ffiValues,
        VALUE* callbackParameters, int callbackCount, VALUE enums)
{
    VALUE callbackProc = Qnil;
    FFIStorage* param = &paramStorage[0];
    int i, argidx, cbidx, argCount;

    if (unlikely(paramCount != -1 && paramCount != argc)) {
        if (argc == (paramCount - 1) && callbackCount == 1 && rb_block_given_p()) {
            callbackProc = rb_block_proc();
        } else {
            rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, paramCount);
        }
    }

    argCount = paramCount != -1 ? paramCount : argc;

    for (i = 0, argidx = 0, cbidx = 0; i < argCount; ++i) {
        Type* paramType = paramTypes[i];
        int type;

        
        if (unlikely(paramType->nativeType == NATIVE_MAPPED)) {
            VALUE values[] = { argv[argidx], Qnil };
            argv[argidx] = rb_funcall2(((MappedType *) paramType)->rbConverter, id_to_native, 2, values);
            paramType = ((MappedType *) paramType)->type;
        }

        type = argidx < argc ? TYPE(argv[argidx]) : T_NONE;
        ffiValues[i] = param;

        switch (paramType->nativeType) {

            case NATIVE_INT8:
                param->s8 = NUM2INT(argv[argidx]);
                ++argidx;
                ADJ(param, INT8);
                break;


            case NATIVE_INT16:
                param->s16 = NUM2INT(argv[argidx]);
                ++argidx;
                ADJ(param, INT16);
                break;


            case NATIVE_INT32:
                if (unlikely(type == T_SYMBOL && enums != Qnil)) {
                    VALUE value = rb_funcall(enums, id_map_symbol, 1, argv[argidx]);
                    param->s32 = NUM2INT(value);

                } else {
                    param->s32 = NUM2INT(argv[argidx]);
                }

                ++argidx;
                ADJ(param, INT32);
                break;


            case NATIVE_BOOL:
                if (type != T_TRUE && type != T_FALSE) {
                    rb_raise(rb_eTypeError, "wrong argument type  (expected a boolean parameter)");
                }
                param->s8 = argv[argidx++] == Qtrue;
                ADJ(param, INT8);
                break;


            case NATIVE_UINT8:
                param->u8 = NUM2UINT(argv[argidx]);
                ADJ(param, INT8);
                ++argidx;
                break;


            case NATIVE_UINT16:
                param->u16 = NUM2UINT(argv[argidx]);
                ADJ(param, INT16);
                ++argidx;
                break;


            case NATIVE_UINT32:
                param->u32 = NUM2UINT(argv[argidx]);
                ADJ(param, INT32);
                ++argidx;
                break;


            case NATIVE_INT64:
                param->i64 = NUM2LL(argv[argidx]);
                ADJ(param, INT64);
                ++argidx;
                break;


            case NATIVE_UINT64:
                param->u64 = NUM2ULL(argv[argidx]);
                ADJ(param, INT64);
                ++argidx;
                break;

            case NATIVE_LONG:
                *(ffi_sarg *) param = NUM2LONG(argv[argidx]);
                ADJ(param, LONG);
                ++argidx;
                break;

            case NATIVE_ULONG:
                *(ffi_arg *) param = NUM2ULONG(argv[argidx]);
                ADJ(param, LONG);
                ++argidx;
                break;

            case NATIVE_FLOAT32:
                param->f32 = (float) NUM2DBL(argv[argidx]);
                ADJ(param, FLOAT32);
                ++argidx;
                break;

            case NATIVE_FLOAT64:
                param->f64 = NUM2DBL(argv[argidx]);
                ADJ(param, FLOAT64);
                ++argidx;
                break;

            case NATIVE_LONGDOUBLE:
                param->ld = rbffi_num2longdouble(argv[argidx]);
                ADJ(param, LONGDOUBLE);
                ++argidx;
                break;


            case NATIVE_STRING:
                if (type == T_NIL) {
                    param->ptr = NULL; 
                
                } else {
                    if (rb_safe_level() >= 1 && OBJ_TAINTED(argv[argidx])) {
                        rb_raise(rb_eSecurityError, "Unsafe string parameter");
                    }

                    param->ptr = StringValueCStr(argv[argidx]);
                }

                ADJ(param, ADDRESS);
                ++argidx;
                break;

            case NATIVE_POINTER:
            case NATIVE_BUFFER_IN:
            case NATIVE_BUFFER_OUT:
            case NATIVE_BUFFER_INOUT:
                param->ptr = getPointer(argv[argidx++], type);
                ADJ(param, ADDRESS);
                break;


            case NATIVE_FUNCTION:
            case NATIVE_CALLBACK:
                if (callbackProc != Qnil) {
                    param->ptr = callback_param(callbackProc, callbackParameters[cbidx++]);
                } else {
                    param->ptr = callback_param(argv[argidx], callbackParameters[cbidx++]);
                    ++argidx;
                }
                ADJ(param, ADDRESS);
                break;

            case NATIVE_STRUCT:
                ffiValues[i] = getPointer(argv[argidx++], type);
                break;

            default:
                rb_raise(rb_eArgError, "Invalid parameter type: %d", paramType->nativeType);
        }
    }
}