2009-05-15 5 views
2

Ich muss eine Textdatei byte-shift. Ich weiß absolut nichts über Perl, aber ich fand ein perfekt funktionierendes Stück Code in Perl namens moz-byteshift.pl (documentation). Das macht genau das, was ich machen möchte, aber ich muss es in C# machen.Hilfe mit Byteverschiebung

Hier ist der Quellcode der Perl-Datei:

#!/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; 
} 

Wenn jemand zumindest könnte erklären, wie der Perl-Skript funktioniert, das wäre toll. Beispielcode des Äquivalents in C# wäre besser. =)

Danke für die Hilfe.

+2

Ich verstehe es nicht. Wenn Sie, wie Sie in einem Kommentar sagen, nicht wirklich wissen, was das Perl-Skript tut, woher wissen Sie, dass es das ist, was Sie tun wollen? – ysth

+0

Dieses Skript wird von einem Mitarbeiter verwendet, um eine Funktion auszuführen, die ich jetzt implementieren muss. So geht das. –

Antwort

1

Was der Code tut ist dies: Lesen Sie jedes Byte von Standard-Eingang eins nach dem anderen (nach dem Umschalten in den Rohmodus, so dass keine Übersetzung auftritt). Der Entpacker erhält den Byte-Wert des gerade gelesenen Zeichens, so dass eine '0' gelesen zu 0x30 wird. Die Codierung latin1 ist so gewählt, dass diese Konvertierung konsistent ist (siehe z. B. http://www.cs.tut.fi/~jkorpela/latin9.html).

Dann wird der Wert in der Befehlszeile mit der Option -s zusammen mit 512 zu diesem Byte hinzugefügt, um eine Modulo-Operation zu simulieren. Auf diese Weise sind -s 0, -s 256 usw. äquivalent. Ich bin nicht sicher, warum das nötig ist, weil ich angenommen hätte, dass das folgende Rudel das erledigt hätte, aber ich denke, dass sie einen guten Grund haben müssen, es dort hinein zu tun.

Schreiben Sie dann das unverarbeitete Byte an den Standardeingang.

Hier ist, was passiert, wenn Sie es auf einer Datei ausgeführt enthält die Zeichen(ich die Daten in dem DATA Abschnitt) setzen:

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

Jedes Byte-Wert wird um eins erhöht.

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

bleiben 257% 256 = 1. Das heißt:

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

zum einzigen Schritt in dem Code verwendet, äquivalent ist.

Viel später: OK, ich weiß nicht, C# aber hier ist, was ich in der Lage war, zusammen mit Online-Dokumentation zusammenzusetzen.Jemand, der C# kennt sollte dieses Problem beheben:

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

Ich denke, dass die 512 eine Voreingenommenheit sein soll, um den Wert zu zwingen, statt zu sättigen. Ich denke nicht, dass es notwendig ist (zumindest nicht in Perl). –

+1

Vielen Dank! Das funktioniert perfekt. Ich werde das nicht von der Kommandozeile aus verwenden, aber für andere, die diese Frage finden, gibt es einen Fehler in Ihrem Code: Sie sollten 'args.Length <1 || hinzufügen ' an den Anfang Ihrer if-Bedingung, um eine" index out of bounds "-Ausnahme zu vermeiden, wenn nichts eingegeben wird. –

+0

Danke für den Fang. –

4

Es gibt nicht viel zu erzählen. Er liest eine Datei ein Byte nach der anderen, passt den Wert jedes Bytes um einen beliebigen Wert an (über das Flag -s angegeben) und schreibt die angepassten Bytes aus. Es ist das binäre Äquivalent der ROT-13-Verschlüsselung einer Textdatei.

Der Rest der Details sind spezifisch wie Perl diese Dinge tut. getopts() ist eine Funktion (aus dem Getopt :: Std-Modul), die Befehlszeilenschalter verarbeitet. binmode() versetzt die Dateihandles in den Raw-Modus, um die Magie zu umgehen, die Perl normalerweise während der I/O-Operationen ausführt. Die Funktionen syread() und syswrite() werden für den Zugriff auf Low-Level-Streams verwendet. Die Funktionen pack() und unpack() werden zum Lesen und Schreiben von Binärdaten verwendet. Perl macht keine nativen Typen.

Das wäre trivial in C neu zu implementieren. Ich würde empfehlen, dies zu tun (und von C# wenn nötig binden), anstatt direkt auf C# zu portieren.

+0

Danke. Das ist hilfreich. Ich denke, der Teil, den ich nicht verstehe, ist, welche Art von Verschiebung es tut. Benötigt es ein Byte Array wie folgt: byte [] {1,2,3,4,5} und (um eins verschoben) ergibt dies: byte [] {5,1,2,3,4}? Oder verschiebt es die Bits jedes Bytes, indem: byte [] {00000001,00000010,00000011} in (um eins): byte [] {10000000,00000001,10000001}? –

+1

Dies eine "Verschiebung" nennen ist eine Art Fehlbezeichnung. Es bewegt keine Bits oder Bytes. Es wendet einen Offset auf den Wert jedes Bytes an. Wenn Ihre ursprünglichen Daten Byte-Werte von 1, 2, 3 hätten und Sie "-s 5" angegeben hätten, wäre das Ergebnis 6, 7, 8. –

+0

Also addiert es sich zum Byte-Wert? Bei einer Verschiebung von 1 wird 00000001 zu 00000010, 00001000 wird zu 00001001 und so weiter? –

1

von den anderen Antworten zu urteilen das Äquivalent in C# würde dies etwas wie folgt aussehen:

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 gibt den Wert des Bytes zurück, oder -1, wenn das Ende des Streams erreicht ist, so dass ein Kommentar keinen Sinn ergibt. – samjudson

+0

Laut http://msdn.microsoft.com/en-us/library/system.io.binaryreader.readbyte.aspx ist der Rückgabewert von ReadByte vom Typ System.Byte. Nach http://msdn.microsoft.com/en-us/library/system.byte.aspx System.Byte "Repräsentiert eine 8-Bit-Ganzzahl ohne Vorzeichen." Es wird nicht erwähnt, dass ReadByte -1 zurückgibt, wenn das Ende des Streams erreicht ist. Tatsächlich stürzte ein einfaches Testprogramm, das auf dem basiert, was Sie oben geschrieben haben, mit System.IO.EndOfStreamException ab. –

+1

Nun bin ich nicht BinaryReader aufrufen. ReadByte bin ich, ich rufe Stream.ReadByte. Überprüfen Sie die Dokumentation: http://msdn.microsoft.com/en-us/library/system.io.stream.readbyte.aspx – samjudson