CloudFlare suffered a massive security issue affecting all of its customers, including Rosetta Code. All passwords not changed since February 19th 2017 have been expired, and session cookie longevity will be reduced until late March.--Michael Mol (talk) 05:15, 25 February 2017 (UTC)

Just in time processing on a character stream

From Rosetta Code
Just in time processing on a character stream is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Given a stream of characters, presumably (simulated) from a keyboard, that contain the separators "formfeed", "linefeed", "tab" and "space" characters. Print out the ith character of the ith tab-field of the ith line of the ith page to reveal a secret password.

Stop processing immediately upon encountering a "!" found uniquely in this i,i,i,i position (least the system self destruct). The "!" may be found/permitted else where however, in which case it should be ignored.

Ideally this can be generalise as follows:

  • The separators (formfeed, linefeed, tab, space) provided from a user supplied array and can include additional/alternative separators, e.g. (formfeed, linefeed, ".", "," ," ",...).
  • These selection criterial is generalised ith,ith,ith,ith to a boolean function of f(page,line,field,word,...) or f(ith,jth,kth,lth,mth,etc...)

Provide a reasonably interesting message to be decoded, e.g. Silence-Dogood. Your choice.

This task was inspired by the movie "National Treasure" with refers to a "book cipher".

C++[edit]

Text used to encode:The Raven - by E.A.Poe

 
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
 
typedef struct {
int s[4];
}userI;
 
class jit{
public:
void decode( std::string& file, std::vector<userI>& ui ) {
std::ifstream f( file.c_str(), std::ios_base::in );
fileBuffer = std::string( ( std::istreambuf_iterator<char>( f ) ), std::istreambuf_iterator<char>() );
f.close();
for( std::vector<userI>::iterator t = ui.begin(); t != ui.end(); t++ ) {
if( !decode( ( *t ).s ) ) break;
}
std::cout << "\n\n";
}
private:
bool decode( int* ui ) {
int l = 0, t = 0, p = 0, c = 0, a = 0;
for( std::string::iterator i = fileBuffer.begin(); i != fileBuffer.end(); i++ ) {
if( p == ui[0] && l == ui[1] && t == ui[2] && c == ui[3] ) {
if( *i == '!' ) return false;
std::cout << *i; return true;
}
if( *i == '\n' ) { l++; t = c = 0; }
else if( *i == '\t' ) { t++; c = 0; }
else if( *i == '\f' ) { p++; l = t = c = 0; }
else { c++;}
}
return false;
}
std::string fileBuffer;
};
void getUserInput( std::vector<userI>& u ) {
std::string h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 "
"0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28";
//std::getline( std::cin, h );
std::stringstream ss( h );
userI a;
int x = 0;
while( std::getline( ss, h, ' ' ) ) {
a.s[x] = atoi( h.c_str() );
if( ++x == 4 ) {
u.push_back( a );
x = 0;
}
}
}
int main( int argc, char* argv[] ) {
std::vector<userI> ui;
getUserInput( ui );
 
jit j;
j.decode( std::string( "theRaven.txt" ), ui );
return 0;
}
 
Output:
Silence-Dogood.

REXX[edit]

The input file used by this REXX program only contains one page (it has no FF or formfeed characters in it),
and the injection of FF characters into the file would be like putting pencil marks into a holy book.

/*REXX pgm extracts characters by using a book cipher from a text file. */
parse arg iFID /*optional name of file (book). */
if iFID=='' then iFID="JIT.TXT" /*Not specified? Then use default*/
errTxt= ' is missing or not a positive integer: ' /*error text string.*/
$='abcdefghijklmnopqrstuvwxyz'; _=$; upper _; $= '0123456789'$ || _
ask='──────────enter four parameters (all positive integers) or QUIT'
pag=1; lin=1; @.= /*assume start of page 1, line 1.*/
/*read the entire book from file.*/
do while lines(iFID)\==0 /*process lines from input stream*/
_=translate(linein(iFID),,'9'x) /*obtain a single line from input*/
if pos('c'x,_)\==0 then do /*was a ff (form-feed) detected? */
pag=pag+1 /*bump page counter for next page*/
lin=1 /*reset the line counter to one. */
end /* [↑] handle finding of formfeed*/
@.pag.lin=_ /*obtain a single line from input*/
lin=lin+1 /*bump the line counter. */
end /*while lines···*/ /* [↑] read entire input stream.*/
?= /*define the phrase to be null.*/
do prompt=0; bad=1 /*get J.I.T. positional numbers. */
say ask; pull y /*obtain the numbers from console*/
if y='QUIT' then exit 0 /*the user wants out of this loop*/
y=space(translate(y,$,$||xrange())) /*allow any sep user wants.*/
parse var y a.1 a.2 a.3 a.4 /*parse the pertinent parameters.*/
if a.1=='QUIT' then exit 0 /*the user wants out of this loop*/
if words(y)>4 then do /*did the user have fingeritis ? */
say 'too many parameters entered.'
iterate prompt
end /*go and try again to get parms. */
do k=1 for 4 /*validate parms {positive ints}.*/
if datatype(a.k,'W') & a.k>0 then iterate /*found a bad parm.*/
say 'parameter ' k errTxt a.k /*issue an error message to term.*/
iterate prompt /*go & ask for another set of #s.*/
a.k=a.k/1 /*normalize the user's number. */
end /*k*/ /* [↑] done with the validations*/
parse var y p l w c /*parse parameters for names. */
x=substr(word(@.p.l,w),c,1) /*extract the character from book*/
if x=='!' then leave /*if the stop char found, done.*/
say right(x '◄─── a letter',46) /*might as well echo char to term*/
 ?=? || x /*append the character to phrase.*/
end /*j*/ /* [↑] go & keep building phrase*/
say '═════►' ? /*display letters found from book*/
/*stick a fork in it, we're done.*/

input   supplied to the console (terminal) by the user   (the commas are optional):

  1,   133,   4,   5
  1,    34,   9,   3
  1,  1377,   2,   2
  1,     4,   8,   4
  1,   265,   3,   5
  1,   413,  10,   2
  1,    10,  12,   1
  1,   144,  10,  10
  1,   571,   4,  12

output   (abbridged)

──────────enter four parameters  (all positive integers)   or   QUIT
  1,   133,   4,   5
                               s ◄─── a letter
──────────enter four parameters  (all positive integers)   or   QUIT

  ·
  ·
  ·

═════► so─true. 

The input file used (the IBM jargon file) in the above REXX program can be found here ───►   Just_in_time_processing_on_a_character_stream/REXX/JIT.TXT.

Tcl[edit]

Works with: Tcl version 8.6
package require Tcl 8.6
 
oo::class create JustInTimeStreamExtract {
variable map counter counters last
constructor {{pageSeparator "\f"} {lineSeparator "\n"} {fieldSeparator "\t"}} {
dict set map $pageSeparator NextPage
dict set map $lineSeparator NextLine
dict set map $fieldSeparator NextField
set counter 1
array set counters {page 0 line 0 field 0 char 0}
set last ""
}
 
method emit {char} {
puts -nonewline $char
set last $char
}
method finished {} {
if {$last ne "\n"} {
puts ""
}
}
 
method stream {{channel stdin} {length 1}} {
try {
while 1 {
set str [read $channel $length]
if {[eof $channel]} break
foreach c [split $str ""] {
if {[dict exists $map $c]} {
my [dict get $map $c]
} else {
my NextChar $c
}
}
}
} trap STOP {} {
# Do nothing
}
my finished
}
 
method NextPage {} {
incr counters(page)
array set counters {line 0 field 0 char 0}
}
method NextLine {} {
incr counters(line)
array set counters {field 0 char 0}
}
method NextField {} {
incr counters(field)
set counters(char) 0
}
method NextChar {char} {
incr counters(char)
if {[my PrintThisOne?]} {
if {$char eq "!"} {
throw STOP "stop character found"
}
incr counter
my emit $char
array set counters {page 0 line 0 field 0 char 0}
}
}
 
method PrintThisOne? {} {
tcl::mathop::== $counter $counters(page) $counters(line) $counters(field) $counters(char)
}
}

Demonstration of use:

[JustInTimeStreamExtract new] stream [open "sample.txt"]

zkl[edit]

Translation of: C++
class FlyBy{
fcn decode(file,tuplets){
codePad:=File(file).read().mode(String); // blob of text
tuplets.pump(Console.print, _decode.fp1(codePad));
println();
}
fcn [private] _decode(idx,codePad){ // idx is (ff,lf,tab,chr) offset info codePad
z:=-1;
foreach n,c in (idx.zip(T("\f","\n","\t"))){
do(n){ if(Void==(z=codePad.find(c,z+1))) return(Void.Stop); }
}
if(z==-1) z=0; // (0,0,0,n)
try{ return(codePad[z + idx[-1] + 1]) }catch{ return(Void.Stop) }
}
}
 
fcn getUserInput{
// I don't know a user would enter this but we have
// a string of 4 item tuplets : (formfeeds, linefeeds, tabs, characters), ...
// each tuplet is an offset into a code pad (text)
h:="0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 "
"0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28";
h.split(" ").pump(List,T(Void.Read,3),
fcn(ff,lf,t,s){ vm.arglist.apply("toInt") });
}
input:=getUserInput();
// our code pad is: http://paulo-jorente.de/text/theRaven.txt
FlyBy.decode("theRaven.txt",input);
Output:
Silence-Dogood.