Помогите со смещением байтов

2

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

Здесь исходный код файла 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 script, это было бы здорово. Пример кода эквивалента в С# будет лучше. =)

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

  • 2
    Я не понимаю Если, как вы говорите в одном комментарии, вы на самом деле не знаете, что делает Perl-скрипт, откуда вы знаете, что это то, что вы хотите сделать?
  • 0
    Этот сценарий используется сотрудником для выполнения функции, которую я теперь должен реализовать. Вот как.
Теги:
byte-shifting

3 ответа

1
Лучший ответ

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

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

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

Вот что происходит, когда вы запускаете его в файле, содержащем символы 012345 (я помещаю данные в раздел 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;

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

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

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                 012345....

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

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, чтобы исключить исключение «индекс вне границ», когда ничего не введено.
Показать ещё 3 комментария
4

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

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

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

  • 0
    Благодарю. Это полезно. Я предполагаю, что часть, которую я не понимаю, - то, какой тип сдвига это делает. Требуется ли для этого байтовый массив, подобный этому: byte [] {1,2,3,4,5} и (смещенный на единицу) выдают это: byte [] {5,1,2,3,4}? Или он сдвигает биты каждого байта, превращая: byte [] {00000001,00000010,00000011} в (сдвигая на единицу): byte [] {10000000,00000001,10000001}?
  • 1
    Называть это «сдвигом» - своего рода неправильное выражение. Он не перемещает биты или байты. Применяет смещение к значению каждого байта. Если ваши исходные данные имеют байтовые значения 1, 2, 3 и вы указали «-s 5», результатом будет 6, 7, 8.
Показать ещё 2 комментария
1

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

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, если достигнут конец потока, поэтому комментировать не имеет смысла.
  • 0
    Согласно msdn.microsoft.com/en-us/library/… возвращаемое значение ReadByte имеет тип System.Byte. Согласно msdn.microsoft.com/en-us/library/system.byte.aspx System.Byte «Представляет 8-разрядное целое число без знака». Нет упоминания о том, что ReadByte возвращает -1, если достигнут конец потока. На самом деле простая тестовая программа, основанная на том, что вы написали выше, потерпела крах с System.IO.EndOfStreamException.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню