Pregunta

Necesito byte cambiar un archivo de texto. No sé absolutamente nada acerca de Perl, pero he encontrado una pieza perfectamente de trabajo de código en Perl llamado moz-byteshift.pl ( documentación ). Esto es exactamente lo que quiero hacer, pero tengo que hacerlo en C #.

Aquí está el código fuente del archivo 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;
}

Si alguien pudiera al menos explicar cómo funciona el script de perl, que sería grande. código de ejemplo del equivalente en C # sería mejor. =)

Gracias por la ayuda.

¿Fue útil?

Solución

Lo que hace el código es el siguiente: Leer cada byte de la entrada estándar de uno en uno (después de ponerlo en modo de prima por lo que no se produce la traducción). El desempaqueta obtiene el valor de byte del carácter que acaba de leer de modo que un '0' leer se convierte en 0x30. La codificación latin1 se selecciona de modo que esta conversión es consistente (por ejemplo, véase http: // www .cs.tut.fi / ~ jkorpela / latin9.html ).

A continuación, se añade el valor especificado en la línea de comandos con la opción -s para este byte, junto con 512 para simular una operación de módulo. De esta manera, -s 0, 256 -s etc son equivalentes. No estoy seguro de por qué esto es necesario porque yo hubiera asumido el siguiente paquete se encargó de eso, pero creo que debe haber tenido una buena razón para ponerlo en ese país.

A continuación, escribir el byte prima a la entrada estándar.

Esto es lo que sucede cuando se ejecuta en un archivo que contiene los caracteres 012345 (pongo los datos en los datos de la sección ):

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

Cada valor de byte se incrementa en uno.

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

Recuerde 257% 256 = 1. Es decir:

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

es equivalente a la única etapa utilizado en el código.

Mucho más tarde: OK, no sé C #, pero aquí es lo que era capaz de reconstruir utilizando documentación en línea. Alguien que sabe C # debe solucionar este problema:

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

Otros consejos

No hay mucho que contar. Se lee un byte de archivos a la vez, se ajusta el valor de cada byte a un valor arbitrario (especificado a través de la bandera -s), y escribe los bytes ajustados. Es el equivalente binario de cifrado ROT-13 de un archivo de texto.

El resto de los detalles son específicos a la forma en Perl hace esas cosas. getopts () es una función (desde el módulo Getopt :: Std) que procesa los interruptores de línea de comandos. binmode () devuelve los identificadores de archivo en el modo sin procesar para omitir cualquiera de la magia que Perl hace normalmente durante I / O. El sysread () y syswrite () funciones se utilizan para el acceso corriente de bajo nivel. El pack () y desempaquetar () se utilizan para leer y escribir datos binarios; Perl no hace los tipos nativos.

Esto sería trivial para volver a implementar en C. Me recomiendo hacer eso (y unirse a ella desde C # si es necesario) en lugar de portar a C # directamente.

A juzgar por las otras respuestas el equivalente en C # sería algo como esto:

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();
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top