Перемещение двоичных данных в / из Perl с помощью SWIG - PullRequest
4 голосов
/ 09 марта 2011

Я пытаюсь упростить перемещение двоичных данных между Perl и моей библиотекой C ++.

Я создал структуру c ++ для передачи двоичных данных:

struct binary_data {
    unsigned long length;
    unsigned char *data;
};

В моем файле интерфейса SWIG для меня есть следующее:

%typemap(in) binary_data * (binary_data temp) {
    STRLEN len;
    unsigned char *outPtr;
    if(!SvPOK($input))
        croak("argument must be a scalar string");
    outPtr = (unsigned char*) SvPV($input, len);
        printf("set binary_data '%s' [%d] (0x%X)\n", outPtr, len, $input);
    temp.data = outPtr;
    temp.length = len;
    $1 = &temp;
}
%typemap(out) binary_data * {
  SV *obj = sv_newmortal();
  if ($1 != 0 && $1->data != 0 && $1->length > 0) {     
    sv_setpvn(obj, (const char*) $1->data, $1->length);
    printf("get binary_data '%s' [%d] (0x%X)\n", $1->data, $1->length, obj);
  } else {
    sv_setsv(obj, &PL_sv_undef);
    printf("get binary_data [set to undef]\n");
  }
  if( !SvPOK(obj) )
    croak("The result is not a scalar string"); 
  $result = obj;
}

Я собираю свой модуль Perl через "ExtUtils :: MakeMaker", и все хорошо.

Затем я запускаю следующий тестовый скрипт perl, чтобы убедиться, что двоичные данные установить / получить из строки perl правильно.

my $fr = ObjectThatContainsBinaryData->new();
my $data = "1234567890"; 
print ">>>PERL:swig_data_set\n"; 
$fr->swig_data_set($data);
print "<<<PERL:swig_data_set\n";
print ">>>PERL:swig_data_get\n"; 
my $rdata = $fr->swig_data_get();
print "<<<PERL: swig_data_get\n";
print "sent    :" . \$data . " len=" . length($data). " '$data'\n"
     ."recieved:". \$rdata.  " len=" . length($rdata). " '$rdata'\n";

Теперь объединенный стандартный вывод printf для C ++ и Perl:

>>>PERL:swig_data_set
set binary_data '1234567890' [10] (0x12B204D0)
<<<PERL:swig_data_set
>>>PERL:swig_data_get
get binary_data '1234567890' [10] (0x1298E4E0)
<<<PERL: swig_data_get
sent    :SCALAR(0x12b204d0) len=10 '1234567890'
recieved:SCALAR(0x12bc71c0) len=0 ''

Так почему же похоже, что вызов perl для sv_setpvn не работает или не работает? Я не знаю, почему, когда я печатаю возвращенные двоичные данные в perl, они отображаются в виде пустого скаляра, но они хорошо выглядят во встроенной карте типов SWIG C ++.

Я использую:

Perl v5.8.8 для x86_64-linux-thread-multi

SWIG 2.0.1

gcc версия 4.1.1 20070105 (Red Hat 4.1.1-52)

Ответы [ 4 ]

2 голосов
/ 17 марта 2011

Если вы замените следующую строку в вашей% typemap (out):

$result = obj;

С

$result = obj; argvi++;  //This is a hack to get the hidden stack pointer to increment before the return

Сгенерированный код SWIG теперь будет выглядеть так:

...
  ST(argvi) = obj; argvi++;
}
XSRETURN(argvi);
}

И ваш тестовый скрипт вернет строку Perl, как и ожидалось.

SV = PV(0x1eae7d40) at 0x1eac64d0
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,POK,pPOK)
  PV = 0x1eb25870 "1234567890"\0
  CUR = 10
  LEN = 16
<<<PERL: swig_data_get
sent    :SCALAR(0x1ea64530) len=10 '1234567890'
recieved:SCALAR(0x1eac64d0) len=10 '1234567890'

Вы должны были более внимательно прочитать документацию SWIG 2.0 по типам карт в Perl:

» 30.8.2 Возвращаемые значения

Возвращаемые значения помещаются в стек аргументов каждой функции-оболочки. Текущее значение указателя стека аргументов содержится в переменной argvi. Всякий раз, когда добавляется новое выходное значение, очень важно, чтобы это значение увеличивалось. Для нескольких выходных значений конечное значение argvi должно быть общим числом выходных значений. «

1 голос
/ 17 мая 2012

swig предоставляет модуль с именем cdata.i.Вы должны включить это в файл определения интерфейса.

Как только вы включите это, он дает две функции cdata() и memmove().Учитывая пустоту * и длину двоичных данных, cdata() преобразует их в строковый тип целевого языка.

memmove() наоборот.если задан строковый тип, он скопирует содержимое строки (включая встроенные нулевые байты) в тип C void *.

Обработка двоичных данных становится намного проще с этим модулем.это то, что вам нужно.

1 голос
/ 10 марта 2011

Что если вы не сделаете это смертным?Я проводил тестирование с Inline :: C (так как я никогда не использовал SWIG), и установка SV на смертельный режим вызывала проблемы, так как Inline :: C делал это для меня.Возможно, SWIG использует похожий дизайн?

Оба

SV* obj = newSV(0);
sv_setpvn(obj, "abc", 3);

и

SV* obj = newSVpvn("abc", 3);

работали с Inline :: C.

0 голосов
/ 10 марта 2011

На стороне Perl, не могли бы вы добавить

use Devel::Peek;
Dump($fr->swig_data_get());

и предоставить вывод?Спасибо.

...