Category Archives: (oo)REXX

MD5 digest in OORexx

usemd5.rex – a sample MD5 calculation with md5.cls below

#!/usr/bin/rexx
 
parse arg ifn   -- get input filename
input_stream = .stream~new(ifn)
message_digest = .md5~new
do while input_stream~chars>0
  -- calculate digest in chunks of 256 bytes
  message_digest~update(input_stream~charin(,256))
end
say message_digest~digest
exit
 
::requires "md5.cls"

md5.cls – a MD5 implementation in OORexx

#!/usr/bin/rexx
 
-- requires OORexx 4.2.0 or later
-- standard numeric digits of 9 is not enough in this case
::options digits 20
 
-- Implementation mainly based on pseudocode in https://en.wikipedia.org/wiki/MD5
::class md5 public
 
::method init
  expose a0 b0 c0 d0 count buffer index K. s  -- instance variables
  use strict arg chunk=""
  -- Initialize message digest
  a0 = .int32~new('67452301'x,"C")   -- A
  b0 = .int32~new('efcdab89'x,"C")   -- B
  c0 = .int32~new('98badcfe'x,"C")   -- C
  d0 = .int32~new('10325476'x,"C")   -- D
  -- The 512 bit chunk buffer
  buffer = .mutablebuffer~new('00'x~copies(64),64)
  -- The position in the buffer to insert new input
  index = 1
  -- message bytecount 
  count = 0 
  -- initialize leftrotate amounts
  nrs = .array~of(7,12,17,22)
  s = nrs~union(nrs)~union(nrs)~union(nrs)
  nrs = .array~of(5,9,14,20)
  s = s~union(nrs)~union(nrs)~union(nrs)~union(nrs)
  nrs = .array~of(4,11,16,23)
  s = s~union(nrs)~union(nrs)~union(nrs)~union(nrs)
  nrs = .array~of(6,10,15,21)
  s = s~union(nrs)~union(nrs)~union(nrs)~union(nrs)
  -- initialize sinus derived constants.
  -- sin function from RXMath Library shipped with OORexx
  -- see ::routine directive at the end of the code 
  do i=0 to 63
    K.i = .int32~new(((2**32)*(sin(i+1,16,R)~abs))~floor) 
  end
  -- process initial string if any
  self~update(chunk)
exit
 
::method update
  expose a0 b0 c0 d0 count buffer index K. s  -- instance variables
  use strict arg chunk
  count += chunk~length
  if chunk~length<65-index then do
    buffer~overlay(chunk,index)
    index += chunk~length
  end
  else do
    split = 65-index+1
    parse var chunk part =(split) chunk
    buffer~overlay(part,index)
    index = 65
  end
  -- Only proces completely filled buffer
  do while index=65
    A = a0
    B = b0
    C = c0
    D = d0
    do i=0 to 63
      select 
        when i<16 then do
          F = D~xor(B~and(C~xor(D)))
          g = i
        end
        when i<32 then do
          F = C~xor(D~and(B~xor(C)))
          g = (5*i+1)//16
        end
        when i<48 then do
          F = B~xor(C)~xor(D)
          g = (3*i+5)//16
        end
        otherwise do
          F = C~xor(B~or(D~not))
          g = (7*i)//16
        end
      end
      M = .int32~new(buffer~substr(g*4+1,4)~reverse,"C")  -- 32bit word in little-endian
      dTemp = D
      D = C
      C = B
      B = (B + (A+F+K.i+M)~bitrotate(s[i+1]))
      A = dTemp
    end
    a0 = a0+A
    b0 = b0+B
    c0 = c0+C
    d0 = d0+D
    parse var chunk part 65 chunk
    index = part~length+1
    buffer~overlay(part,1,part~length)
  end
exit
 
::method digest
  expose a0 b0 c0 d0 count buffer index K s -- instance variables
  padlen = 64
  if index<57 then padlen = 57-index
  if index>57 then padlen = 121-index
  padding = '00'x~copies(padlen)~bitor('80'x)
  bitcount = count*8//2**64
  lowword = bitcount//2**32
  hiword = bitcount%2**32
  lowcount = lowword~d2c(4)~reverse -- make it little-endian
  hicount = hiword~d2c(4)~reverse   -- make it little-endian
  self~update(padding || lowcount || hicount)
return a0~string || b0~string || c0~string || d0~string
 
-- A convenience class to encapsulate operations on non OORexx-like
-- things such as little-endian 32-bit words  
::class int32 private
 
::attribute arch class
 
::method init class
  self~arch = "little-endian"   -- can be adapted for multiple architectures 
 
-- Method to create an int32 like object
-- Input can be a OORexx whole number (type="I") or
-- a character string of 4 bytes (type="C")
-- input truncated or padded to 32-bit word/string
::method init
  expose char4 int32
  use strict arg input, type="Integer"
  -- type must be one of "I"nteger or "C"haracter
  t = type~subchar(1)~upper
  select
    when t=='I' then do
      char4 = input~d2c(4)
      int32 = char4~c2d
    end
    when t=='C' then do
      char4 = input~right(4,'00'x)
      int32 = char4~c2d
    end
    otherwise do
      raise syntax 93.915 array("IC",type)
    end
  end
exit
 
::method xor  -- wrapper for OORexx bitxor method
  expose char4
  use strict arg other
return .int32~new(char4~bitxor(other~char),"C")
 
::method and  -- wrapper for OORexx bitand method
  expose char4
  use strict arg other
return .int32~new(char4~bitand(other~char),"C")
 
::method or   -- wrapper for OORexx bitor method
  expose char4
  use strict arg other
return .int32~new(char4~bitor(other~char),"C")
 
::method not   -- OORexx not implementation
  expose char4
return .int32~new(char4~bitxor('ffffffff'x),"C")
 
::method bitleft -- OORexx shift (<<) implementation
  expose char4 
  use strict arg bits
  bstring = char4~c2x~x2b 
  bstring = bstring~substr(bits+1)~left(bstring~length,'0') 
return .int32~new(bstring~b2x~x2d) 
 
::method bitright -- OORexx shift (>>) implementation
  expose char4
  use strict arg bits, signed=.false
  bstring = char4~c2x~x2b
  fill = '0'
  if signed then fill = bstring~subchar(1)
  bstring = bstring~left(bstring~length-bits)~right(bstring~length,fill)
return .int32~new(bstring~b2x~x2d)
 
::method bitrotate  -- OORexx (left) rotate method
  expose char4
  use strict arg bits, direction='left'
  d = direction~subchar(1)~upper
  if d=='L' then do
    leftpart = self~bitleft(bits)
    rightpart = self~bitright(32-bits)
  end
  else do
    leftpart = self~bitleft(32-bits)
    rightpart = self~bitright(bits)
  end
return rightpart~or(leftpart)
 
::method int  -- retrieve integer as number
  expose int32
return int32
 
::method char -- retrieve integer as characters
  expose char4
return char4
 
::method string -- retrieve integer as hexadecimal string
  expose char4
return char4~reverse~c2x~lower
 
::method '+'  -- OORexx method to add 2 .int32 instances
  expose int32
  use strict arg other
return .int32~new(int32+other~int)
 
-- Simplify function names for the necessary 'RxMath' functions	
::routine sin EXTERNAL "LIBRARY rxmath RxCalcSin"
Posted in (oo)REXX Tagged

ooRexx 4.1.3 – Classes & Methods

An online reference for ooRexx (Release 4.1.3) classes and their methods.

Posted in (oo)REXX

REXX Gevonden Voorwerpen

Een lichtgewicht REXX dingetje, dat ik ongeveer 10 jaar geleden schreef en terugvond op een oude harde schijf:

#!/usr/bin/rexx
--
-- A Generalized Rexx Filter that can be used in a pipe
--
-- Usage: rexx filter.rex builtin-or-external-function-name(arg1, arg2, ...)
--    or: rexx filter.rex < inputfile
--    or: rexx filter.rex (boolean expression) 
--
-- Note 1:
--
--    rexx (to invoke filter.rex) may or may not be required to get 
--    the redirection and piping working, dependent on the operating
--    system and the REXX implementation and/or installation setup.  
--  
-- External functions can have a simple structure, for instance: 
--          
--    rexx filter.rex "cut.rex(!line,10:5)" or filter.rex "cut(!line,10:5)"
--
--    parse arg line,poslen
--    parse var poslen pos ':' length .
--    /* possibly more logic, but return value should be a (modified)
--       line or a boolean if the function is called as an expression */
--    return delstr(line,pos,length)  
--  
-- Argument(s)/Option(s) or even all of the filter have to be quoted generally.
-- On Windows: It's best to use '"' for all of the filtere and "'" for arguments.
-- On *n?x: It's best to use "'" for all of the filter and '"' for arguments.
-- On *n?x: Redirection (< and > or >> ) doesn't seem to work all of the time.
--
-- Pipe variables:
--
-- The input line from the pipe is represented by '!line'. 
-- The running line count is represented by '!count' 
-- The total nr of lines is respresented by '!lines'
-- Using '!lines' in the filter implies buffering the input stream before 
-- any output is passed on to the next pipe stage.
--
-- Example 1: rexx filter.rex changestr(needle,!line,newneedle)
--
-- Example 2: rexx filter.rex strip(!line,'L','>')
--
-- Example 3: rexx filter.rex < somefile.txt  - just echoes the input
--
-- Example 4: rexx filter.rex (pos('>',!line)>0) - a boolean expression 
--
-- Example 5: rexx filter.rex "(!count>10)" - skips first 10 lines of input
--
-- Example 6: rexx filter.rex "(!count>!lines-10)" - shows last 10 lines of input   
--
--    rexx filter.rex <filter.rex | ,
--    rexx filter.rex (pos('-',!line)=1) | , 
--    rexx filter.rex strip(!line,'L','-')
-- 
-- will first read and echo filter.rex, 
-- then output only input lines that start with '-',
-- then strip leading comment identifier '--'. 
--
-- No copyright, no license, no guarantees, use at your own risk.
--
-- And you just read the result of the pipe above.
--
parse source . . me  
parse arg !filter
do (!filter='?' | !filter='-?' | !filter='/?' | !filter='h' | !filter='-h' | !filter='/h' | !filter='--help')
  pipe = 'rexx "'me'"<"'me'" | rexx "'me'" (pos(''-'',!line)=1) | rexx "'me'" strip(!line,''L'',''-'')'
  pipe
  exit
end
!filter = strip(strip(strip(!filter,'B',' '),'B',"'"),'B','"')  -- strip spaces and quotes
do until (lines()>0)  -- a buffered stage can delay the input stream 
  nop
end 
!buffered = (pos('!lines',!filter)>0)
if (!buffered) then do  -- buffer input stream on standard queue
  do !lines=1 by 1 while (lines()>0)
    queue linein()
  end
  !lines = queued()
  !queued = !lines
  if (!queued>0) then do  -- prefetch the 1st line queue
    parse pull !line
  end  
end
else do
  !queued = lines()
  if (!queued>0) then do  -- prefetch the 1st line from stdin
    !line = linein()
  end) 
end
do !count=1 by 1 while (!queued>0)
  if (!filter = '') then do  -- no filter just echoes the input
    !out = !line
  end
  else do 
    if (substr(!filter,1,1)='(') then do
      drop !out    -- to verify !out is a var later on            
      interpret '!test =' !filter  -- apply the test
      if (!test) then do   -- if test yields .true it goes out
        !out = !line
      end
    end
    else do    -- apply the filter
      interpret '!out =' !filter  
    end
  end
   if (var("!out")) then do  -- only write if we have something 
     call lineout ,!out     
  end
  if (!buffered) then do  -- if buffered, next line from queue
  !queued = queued()
  if (!queued>0) then do
    parse pull !line
  end
  end
  else do  -- not buffered, next line from stdin
    !queued = lines()
  if (!queued>0) then do
    !line = linein()
  end
  end
end
exit

De 1-regel commentaar ( ” –” ) stijl kan het gebruik van bovenstaande wellicht beperken tot ooREXX en Regina REXX.

Posted in (oo)REXX Tagged , , , , ,