2009-05-15 3 views
2

Мне нужно поменять текст в байтах. Я абсолютно ничего не знаю о perl, но я нашел отлично работающий фрагмент кода в perl под названием moz-byteshift.pl (documentation). Это делает именно то, что я хочу сделать, но мне нужно сделать это на C#.Справка по смещению байтов

Вот исходный код файла PERL:

#!/usr/bin/perl 

# To perform a byteshift of 7 
# To decode: moz-byteshift.pl -s -7 <infile >outfile 
# To encode: moz-byteshift.pl -s 7 <infile >outfile 

# To perform a byteshift of 13 
# To decode: moz-byteshift.pl -s -13 <infile >outfile 
# To encode: moz-byteshift.pl -s 13 <infile >outfile 

use encoding 'latin1'; 
use strict; 
use Getopt::Std; 

use vars qw/$opt_s/; 

getopts("s:"); 
if(!defined $opt_s) { 
    die "Missing shift\n"; 
} 

my $buffer; 
while(1) { 
    binmode(STDIN, ":raw"); 
    my $n=sysread STDIN, $buffer, 1; 
    if($n == 0) { 
    last; 
    } 
    my $byte = unpack("c", $buffer); 
    $byte += 512 + $opt_s; 
    $buffer = pack("c", $byte); 
    binmode(STDOUT, ":raw"); 
    syswrite STDOUT, $buffer, 1; 
} 

Если кто-то мог бы по крайней мере объяснить, как работает скрипт на Perl, это было бы здорово. Пример кода эквивалента в C# будет лучше. =)

Спасибо за помощь.

+2

Я не понимаю. Если, как вы говорите в одном комментарии, вы действительно не знаете, что делает скрипт perl, откуда вы знаете, что это то, что вы хотите сделать? – ysth

+0

Этот скрипт используется сотрудником для выполнения функции, которую я теперь должен реализовать. Вот как. –

ответ

1

Что делает этот код: Прочитайте каждый байт со стандартного ввода один за другим (после его переключения в необработанный режим, чтобы не было перевода). Распаковка получает значение байта только что прочитанного символа, так что чтение «0» превращается в 0x30. Кодировка latin1 выбирается так, чтобы это преобразование было согласованным (например, см. http://www.cs.tut.fi/~jkorpela/latin9.html).

Затем значение, указанное в командной строке с опцией -s, добавляется к этому байту вместе с 512 для имитации операции модуля. Таким образом, -s 0, -s 256 и т. Д. Эквивалентны. Я не уверен, почему это необходимо, потому что я предполагал, что следующий пакет позаботился об этом, но я думаю, что у них, должно быть, были веские причины, чтобы поместить его туда.

Затем напишите исходный байт на стандартный ввод.

Вот что происходит, когда вы запускаете его на файл, содержащий символы(я поместить данные в разделе DATA):

E:\Test> byteshift.pl -s 1 | xxd 
0000000: 3132 3334 3536 0b      123456. 

Каждое значение байта увеличивается на единицу.

E:\Test> byteshift.pl -s 257 | xxd 
0000000: 3132 3334 3536 0b      123456. 

Запомнить 257% 256 = 1. То есть:

$byte += $opt_s; 
$byte %= 256; 

эквивалентен одной стадии, используемой в коде.

Много позже: ОК, я не знаю C#, но вот что мне удалось собрать вместе с помощью онлайн-документации.Кто-то, кто знает C# это исправить:

using System; 
using System.IO; 

class BinaryRW { 
    static void Main(string[] args) { 
     BinaryWriter binWriter = new BinaryWriter(
       Console.OpenStandardOutput() 
       ); 
     BinaryReader binReader = new BinaryReader(
       Console.OpenStandardInput() 
       ); 

     int delta; 

     if (args.Length < 1 
       || ! int.TryParse(args[0], out delta)) 
     { 
      Console.WriteLine(
        "Provide a non-negative delta on the command line" 
        ); 
     } 
     else {  
      try { 
       while (true) { 
        int bin = binReader.ReadByte(); 
        byte bout = (byte) ((bin + delta) % 256); 
        binWriter.Write(bout); 
       } 
      } 

      catch(EndOfStreamException) { } 

      catch(ObjectDisposedException) { } 

      catch(IOException e) { 
       Console.WriteLine(e);   
      } 

      finally { 
       binWriter.Close(); 
       binReader.Close(); 

      } 
     } 
    } 
} 

E:\Test> xxd bin 
0000000: 3031 3233 3435 0d0a 0d0a    .... 

E:\Test> b 0 < bin | xxd 
0000000: 3031 3233 3435 0d0a 0d0a    .... 

E:\Test> b 32 < bin | xxd 
0000000: 5051 5253 5455 2d2a 2d2a     PQRSTU-*-* 

E:\Test> b 257 < bin | xxd 
0000000: 3132 3334 3536 0e0b 0e0b     123456.... 
+1

Я думаю, что 512 предполагается смещением, чтобы заставить значение обернуть вместо насыщения. Я не думаю, что это необходимо, хотя (по крайней мере, не в Perl). –

+1

Спасибо! Это работает отлично. Я не буду использовать это из командной строки, но для других, которые находят этот вопрос, в вашем коде есть одна ошибка: Вы должны добавить 'args.Length <1 || ' в начало вашего условия if, чтобы исключить исключение« index out of bounds », когда ничего не введено. –

+0

Спасибо, что поймали это. –

4

Не так много сказать. Он считывает файл по одному байту за раз, настраивает значение каждого байта на произвольное значение (задается с помощью флага -s) и записывает отрегулированные байты. Это двоичный эквивалент шифрования ROT-13 текстового файла.

Остальные детали относятся к тому, как Perl делает эти вещи. getopts() - это функция (из модуля Getopt :: Std), которая обрабатывает ключи командной строки. binmode() помещает дескрипторы файлов в режим raw, чтобы обойти любую магию, которую Perl обычно делает во время ввода-вывода. Функции sysread() и syswrite() используются для доступа к потоку низкого уровня. Функции pack() и unpack() используются для чтения и записи двоичных данных; Perl не использует собственные типы.

Это было бы тривиально для повторной реализации на C. Я бы рекомендовал сделать это (и привязать его к C#, если это необходимо), а не портировать на C# напрямую.

+0

Спасибо. Это полезно. Я предполагаю, что часть, которую я не понимаю, - это то, что она делает. Требуется ли такой массив байтов: byte [] {1,2,3,4,5} и (сдвинутый на единицу): this: byte [] {5,1,2,3,4}? Или он сдвигает бит каждого байта, поворачивая: byte [] {00000001,00000010,00000011} в (смещение на единицу): byte [] {10000000,00000001,10000001}? –

+1

Вызов этого «сдвига» является своего рода неправильным. Он не перемещает биты или байты. Он применяет смещение к значению каждого байта. Если ваши исходные данные имели байтовые значения 1, 2, 3, и вы указали «-s 5», результат будет 6, 7, 8. –

+0

. Таким образом, он добавляет значение байта? Итак, со сдвигом 1, 00000001 становится 00000010, 00001000 становится 00001001 и т. Д.? –

1

Судя по другим ответам эквивалент в C# будет выглядеть примерно так:

using(Stream sIn = new FileStream(inPath)) 
{ 
    using(Stream sOut = new FileStream(outPath)) 
    { 
    int b = sIn.ReadByte(); 
    while(b >= 0) 
    { 
     b = (byte)b+1; // or some other value 
     sOut.WriteByte((byte)b); 
     b = sIn.ReadByte(); 
    } 
    sOut.Close(); 
    } 
    sIn.Close(); 
} 
+0

ReadByte возвращает значение байта, или -1, если конец потока достигнут, поэтому вы комментируете смысл. – samjudson

+0

В соответствии с http://msdn.microsoft.com/en-us/library/system.io.binaryreader.readbyte.aspx возвращаемое значение ReadByte имеет тип System.Byte. Согласно http://msdn.microsoft.com/en-us/library/system.byte.aspx System.Byte «Представляет 8-разрядное целое без знака». Нет упоминания о ReadByte, возвращающем -1, если конец потока достигнут. На самом деле простая тестовая программа, основанная на том, что вы написали выше, разбилась на System.IO.EndOfStreamException. –

+1

Ну, я не звоню в BinaryReader.ReadByte Я, я звоню в Stream.ReadByte. Проверьте документы: http://msdn.microsoft.com/en-us/library/system.io.stream.readbyte.aspx – samjudson

Смежные вопросы