Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid

Re: 3-D Stereogram, Self replicating source.

by Hero Zzyzzx (Curate)
on Oct 15, 2001 at 23:16 UTC ( #118971=note: print w/replies, xml ) Need Help??

in reply to 3-D Stereogram, Self replicating source.

Umm, that's amazing. Very cool. Can you give up a little bit about how this sucker works?

-Any sufficiently advanced technology is
indistinguishable from doubletalk.

  • Comment on Re: 3-D Stereogram, Self replicating source.

Replies are listed 'Best First'.
Re: Re: 3-D Stereogram, Self replicating source.
by John M. Dlugosz (Monsignor) on Oct 16, 2001 at 03:34 UTC
    My cursory examination is that the general idea is to have the real program along the left edge, and then the rest of the line contains repeated copies of that, modified to show the image.

    In the last 3 lines before the DATA, you can see that since the real line ends with a # so everything after that is ignored.

    The rest of the program works the same way, but is obfuscated by using different characters. Everything between the first 2 commas is a string. The bottom part, which cannot be cloaked the same way hence the major hint in the form of #'s, processes the text string thus:

    tr[|zY!%x][,Q]; s[Q.*\n][]g; eval;
    Which basically changes |,Y,or% into , and changes z,!,or x into Q (more on that next), and throws away a few other letters, which give him padding that can be anywhere including in the "real" code.

    |'s etc. become commas. They were escaped out so that the q could use them to delimit the string

    . The Q, previously z,!,x (or already Q), turns into the new comment character -- everything starting from a Q or z is removed. Having four choices makes it less obvious that each "real" part of a line ends in this.

    Note that such ender character forms a solid vertical stripe in the 14th column, so this code could have processed it by taking 14 chars and throwing away the rest. It's just a matter of changing the last 3 lines. Those lines are shorter than 13 chars, but garbage can be added after # and it works just the same, making the real code in the first "column" that gets replicated and munged to hold the image. Having no image in the topmost line simplifies things, and should be there for a border anyway. —John

      Your analysis is entirely correct, with the exception of the tr/// oversight someone else already pointed out. If anyone wants to see the de-mangling of the string, start up the perl debugger
      perl -d
      and 'W'atch $_
      W $_
      and step by step down towards the eval with the 'n' command. It should be obvious as soon as you see the line of Q's. Next it removes everything from the Q's to end of line. You'll be left with:
      my(@f,@c,@w);@a=@f=<DATA>;seek(DATA,0,0);@c=<DATA>; until(($_=pop(@c))=~/^_/){};unshift(@a,$_);for(1..3) {print(shift(@c));}for(@f){my($s);split//; $_=shift(@c);$_=~s/(.{15}).*/\1/;@w=split//;for(@_) {$w[$s+15-$_]=(($w[$s]eq",")?".":$w[$s]);$s++;} for(1..75){unless($w[$_]ne''){$w[$_]=$w[($_-1)];}} print(join"",@w);print"\n";}print@a;
      With decent space, comments, and more meaningfull variable names...This is for education only; wont work unless in proper shape, with DATA available.
      my(@f,@c,@w); @a=@f=<DATA>; #Read everything from __DATA__ onward into #array @f and @a seek(DATA,0,0); #Seek to begin of source file @c=<DATA>; #Read it all into @c , #!, DATA, and all until( ($_=pop(@c)) =~ /^_/ ){}; #This removes one line at a time from the end # of the source copy in @c, until the line # removed begins with an underscore (i.e. __DATA__ #Now, all that remains in @c is the actuall code; #all __DATA__ and the __DATA__ marker itself have #been removed. unshift(@a,$_); # $_, which still contains the string "__DATA__" we #removed from @c, gets placed at the beginning of @a. We # now have @c, which contains everything in the file up to # the last eval line, @a, which contains the "__DATA__" line # and all of the DATA, and @f which contains just the DATA # contents for(1..3){ #Just do this three times print(shift(@c)); #pop of the top three lines of source and #print them. e.g., "#!/usr/bin/perl", copyright notice, and } # the four hashmarks to align your eyes. for(@f){ # once for each line of DATA my($s); #Remember, 'my' will undef the scalar out everytime # this is reached. Could just as easily be $s=0; split//;#Split it up into an array byte-by-byte. If the #string was "1234", @_ would equal ('1', '2', '3', '4' +) $_=shift(@c); #Grab the next line of code.... $_=~s/(.{15}).*/\1/; #Chop off everything after 15 charachters +. @w=split//; #Split up those 15 charachters into a 15 element a +rray #and put into @w for(@_) # For each letter of the current line pulled from DATA +... {$w[$s+15-$_]=(($w[$s]eq",")?".":$w[$s]); #Err, thats a big one. Remember, the closer the the vi +ewer #you want that character to be, the closer together th +e #charachters that make up that plotted character have +to #be. Also, I am trapping ','s here, because if one fin +ds #its way into the jumble, it'll throw off the quoting +and #ruin the script. Most people won't notice the differe +nce #between the two when staring unless they know to look +. I #would have preffered to use 'ell' and 'one', but cant + use #them as quoting characters. $s++; #and go down the line one by one. } for(1..75){ #the images are 75 charachters wide. For each one. +.. unless($w[$_]ne'') { #If no charachter was put there.. +. $w[$_]=$w[($_-1)]; #put in a copy of the one t +o #the left } } print(join"",@w); # Print out our line we just made. print"\n"; #goto next line, Lather, rinse, repeat. } print@a; #Finally, print the __DATA__ label, and original DATA content +s
      Things I should have done differently: The first my(...) was totally unneeded. I didn't use strict or -w, so this should have gone out the window. I should have used if instead of unless where possible. 4 wasted charachters each. $s-=$s or $s^=$s would have been more fun than my($s) and done the same thing Since the charachters in the DATA section get added in a numeric scalar context, that means that anything not a digit equates to 0. So, instead of bunches of 0's, I could do anything, even making harder to read the data some like this smiley: Feel free to try it.
      __DATA__ llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll llllllllllllllllllllllll1111111lllllllllllllllllllllllllllll lllllllllllllllllll111111111111111111lllllllllllllllllllllll lllllllllllllllll1111111111111111111111lllllllllllllllllllll lllllllllllllll11111ll111111111111ll11111lllllllllllllllllll llllllllllllll111111ll111111111111ll111111llllllllllllllllll lllllllllllll1111111ll111111111111ll1111111lllllllllllllllll llllllllllll11111111ll111111111111ll11111111llllllllllllllll llllllllllll11111111ll111111111111ll11111111llllllllllllllll lllllllllll111111111ll111111111111ll111111111lllllllllllllll lllllllllll1111111111111111111111111111111111lllllllllllllll llllllllll1111l11111111111111111111111111l1111llllllllllllll lllllllllll111ll111111111111111111111111ll111lllllllllllllll lllllllllll1111ll1111111111111111111111ll1111lllllllllllllll llllllllllll1111ll11111111111111111111ll1111llllllllllllllll llllllllllll11111lll1111111111111111lll11111llllllllllllllll lllllllllllll11111lllll1111111111lllll11111lllllllllllllllll llllllllllllll111111llllllllllllllll111111llllllllllllllllll lllllllllllllll11111111llllllllll11111111lllllllllllllllllll lllllllllllllllll1111111111111111111111lllllllllllllllllllll lllllllllllllllllll111111111111111111lllllllllllllllllllllll llllllllllllllllllllllll1111111lllllllllllllllllllllllllllll llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll

      Edit: chipmunk 2001-11-12

      That's a good analysis of the code. I just have one correction. tr[|zY!%x][,Q];
      You said that this changes | Y % into , and z ! x into Q. Actually, it changes | into , and z Y ! % x into Q. When a translation specifies more characters on the left than on the right, the last character on the right is used for all the extras. (With the /d modifier, the extras are deleted from the target string instead.)

      perlop explains the tr/// operator in greater detail.

        last char replicated, not whole sequence repeats: gotcha. Thanks.


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://118971]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (4)
As of 2018-05-26 02:41 GMT
Find Nodes?
    Voting Booth?