質問
テキストファイルをバイトシフトする必要があります。私は Perl についてまったく何も知りませんが、Perl で完全に動作するコードを見つけました。 moz-byteshift.pl (ドキュメンテーション)。これはまさに私がやりたいことを実行しますが、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# の同等のサンプル コードの方が適切です。=)
助けてくれてありがとう。
解決
コードの内容は次のとおりです。標準入力から各バイトを 1 つずつ読み取ります (変換が行われないように raw モードに切り替えた後)。アンパックでは、読み取られたばかりの文字のバイト値が取得されるため、「0」の読み取りは 0x30 になります。latin1 エンコーディングは、この変換に一貫性があるように選択されます (例:見る http://www.cs.tut.fi/~jkorpela/latin9.html).
次に、コマンド ラインで -s オプションを使用して指定された値が 512 とともにこのバイトに追加され、モジュラス演算をシミュレートします。このように、-s 0、-s 256 などは同等です。次のパックがそれを処理すると思っていたので、なぜこれが必要なのかはわかりませんが、これを入れるのには十分な理由があったに違いないと思います。
次に、生のバイトを標準入力に書き込みます。
文字 012345 を含むファイルに対して実行するとどうなるかは次のとおりです (データを データ セクション):
E:\Test> byteshift.pl -s 1 | xxd
0000000: 3132 3334 3536 0b 123456.
各バイト値は 1 ずつ増加します。
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 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つのバイトを読み出す(-sフラグを介して指定される)任意の値で各バイトの値を調整し、調整されたバイトを書き込みます。これは、テキストファイルのROT-13暗号化のバイナリ同等です。
詳細の残りの部分は、Perlはそれらのものをどうするかに固有のものです。 getoptsは()コマンドラインスイッチを処理(Getoptの:: STDモジュールからの)関数です。 binmode()は、Perlは通常I / Oの間にありません魔法のいずれかをバイパスするrawモードでファイルハンドルを置きます。 sysread()およびsyswrite()関数は、低レベルのストリーム・アクセスのために使用されます。パック()および()関数はバイナリデータを読み書きするために使用されるアンパック。 Perlはネイティブ型をしません。
これは、私はそれをやって(および必要であればC#のから、それに結合する)のではなく、直接C#への移植をお勧めしますC.で再実装するのは簡単だろう。
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();
}