Search code examples
c#perlbyte-shifting

Help with byte shifting


I need to byte-shift a text file. I know absolutely nothing about perl, but I found a perfectly working piece of code in perl called moz-byteshift.pl (documentation). This does exactly what I want to do, but I need to do it in C#.

Here's the source code of the perl file:

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

If someone could at least explain how the perl script works, that would be great. Sample code of the equivalent in C# would be better. =)

Thanks for the help.


Solution

  • What the code does is this: Read each byte from standard input one by one (after switching it into raw mode so no translation occurs). The unpack gets the byte value of the character just read so that a '0' read turns into 0x30. The latin1 encoding is selected so that this conversion is consistent (e.g. see http://www.cs.tut.fi/~jkorpela/latin9.html).

    Then the value specified on the command line with the -s option is added to this byte along with 512 to simulate a modulus operation. This way, -s 0, -s 256 etc are equivalent. I am not sure why this is needed because I would have assumed the following pack took care of that but I think they must have had good reason to put it in there.

    Then, write the raw byte out to standard input.

    Here is what happens when you run it on a file containing the characters 012345 (I put the data in the DATA section):

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

    Each byte value is incremented by one.

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

    Remember 257 % 256 = 1. That is:

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

    is equivalent to the single step used in the code.

    Much later: OK, I do not know C# but here is what I was able to piece together using online documentation. Someone who knows C# should fix this:

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