Jump to content

Recommended Posts

Posted (edited)

I wanted some kind of a plugin system for a project I'm working on.

So naturally I decided to write my own from scratch. Stupid.

I actually know of better ways to do this such as...

...But I thought, since I spent several days on this, and it does technically work for my purposes I may as well post it up and maybe some part of it might help someone someday. 

 

;#NoTrayIcon
#include <Math.au3>
#include <File.au3>
#include <Misc.au3>
#include <Crypt.au3>
#include <Array.au3>
#include <FileConstants.au3>
#include <MsgboxConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#Include <GDIPlus.au3>

Global $procs[256][256]
Global $loops[256][256]
Global $v[65000]
Global $a[256][256]
Global $hotkey[100]
Global $hotproc[100]

Func HotkeyPlugin()
  for $hki = 0 to ubound($hotkey)-1
    if @HotKeyPressed == $hotkey[$hki] then
      ExecuteProc($hotproc[$hki])
    endif
  next
EndFunc


Func ImportPlugin()
  local $path = "c:\plugin.au3p"
  local $file = FileOpen($path, $FO_READ)
  local $read = FileRead($file)
  FileClose($file)
  local $nread = Stringsplit($read, @CRLF, 2)
  if Stringleft($nread[0],1) == "'" then
    $nread = stringtrimleft($nread[0],1)
    $nread = stringtrimright($nread,1)
  Else
    $nread = $nread[0]
  endif
  $read = BinaryToString(_Crypt_DecryptData($nread, "a", $CALG_AES_256))
  $read = Stringsplit($read, @CRLF, 2)
  AnalyzePlugin($read)
EndFunc


Func AnalyzePlugin($read)
  local $procnum = 0
  local $loopnum = -1
  local $temp
  local $temp1
  local $ln = 0
  local $lnloop[256]
  local $embedded = -1
  local $hki = 0


  for $r in $read
    $temp = Stringsplit($r, " ", 2)
    $temp1= stringleft($r, 4)
    ;msgbox(64,"temp1",$temp1)
    if $temp1 == "proc" Or $temp1 == "Proc" then
      $procnum = $temp[1]
      $embedded = -1
      $ln = 0
    elseif $temp1 == "endp" Or $temp1 == "Endp" then
      ;msgbox(64,"r",$r)
      $procs[$procnum][$ln] = $r
      $procnum = ""
      $embedded = -1
    elseif $temp1 == "hkps" Or $temp1 == "Hkps" then ;hot key pressed set
      $hotkey[$hki] = $temp[1]
      $hotproc[$hki] = $temp[2]
      $hki = $hki + 1
      HotKeySet($temp[1],"HotkeyPlugin")
    elseif StringStripWS($r, $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES) == "loop" Or StringStripWS($r, $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES) == "Loop" then
      $oldloopnum = $loopnum
      $loopnum = $loopnum + 1
      $embedded = $embedded + 1
      $lnloop[$embedded] = 0
      if $embedded == 0 then
        $procs[$procnum][$ln] = "loop " & $loopnum
        $ln = $ln + 1
      else
        ;msgbox(64,"loop found," & $loopnum, $embedded & " " & $lnloop[$embedded])
        $loops[$oldloopnum][$lnloop[$embedded-1]] = "loop " & $loopnum
        $lnloop[$embedded-1] = $lnloop[$embedded-1] + 1
        ;_arraydisplay($loops)
      endif
    elseif StringStripWS($r, $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES) == "endl" Or StringStripWS($r, $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES) == "Endl" then
      $loops[$loopnum][$lnloop[$embedded]] = StringStripWS($r, $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES)
      $embedded = $embedded - 1
      if $embedded > -1 then
        $loopnum = $loopnum - 1
      endif
    else ; regular code
      if $procnum <> "" then
        if $r <> "" then
          if $embedded == -1 then
            $procs[$procnum][$ln] = StringStripWS($r, $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES)
            $ln = $ln + 1
          else
            $loops[$loopnum][$lnloop[$embedded]] = StringStripWS($r, $STR_STRIPLEADING + $STR_STRIPTRAILING + $STR_STRIPSPACES)
            $lnloop[$embedded] = $lnloop[$embedded] + 1
          endif
        endif
      endif
    endif
  next
  ;_arraydisplay($procs)
  ;_arraydisplay($loops)

  ExecuteProc(0)
EndFunc


Func ExecuteProc($number, $arg1 = "", $arg2 = "")
  local $temp
  local $temp1
  local $return
  local $ift = ""
  local $embeddedif = 0
  local $command = ""

  for $pcount = 0 to 255
    ;put loops in the right places!
    $read = $procs[$number][$pcount]

    ;msgbox(64,"readsays "& $pcount,$read)
    $r = Stringsplit($read, " ", 2)
    $command = stringleft($read, 4)
    ExecuteCode($read, $r, $arg1, $arg2, $temp, $temp1, $return, $ift, $embeddedif, $command)
  next
  return $return
EndFunc



Func ExecuteLoop($number, Byref $arg1, Byref $arg2, Byref $temp, Byref $temp1, Byref $return, Byref $command)
  local $embeddedif = 0
  local $ift = ""
  ;_arraydisplay($procs)
  while 1
    For $pcount = 0 to 255
      ;put loops in the right places!
      $read = $loops[$number][$pcount]
      $r = Stringsplit($read, " ", 2)
      $command = stringleft($read, 4)
      ;msgbox(64,"readsays " & $pcount,$read & " " & $embeddedif & " " & $ift)
      $ret = ExecuteCode($read, $r, $arg1, $arg2, $temp, $temp1, $return, $ift, 0, $command)
      if $ret == 300 then
        $pcount = 300
      elseif $ret == "bklp" then
        exitloop 2
      endif
    next
  wend

EndFunc



Func ExecuteCode(Byref $read, Byref $r, Byref $arg1, Byref $arg2, Byref $temp, Byref $temp1, Byref $return, Byref $ift, Byref $embeddedif, Byref $command)
  local $tempread1
  local $tempread2
  local $tempread3
  local $execute1 = false
  local $execute2 = false
  local $execute3 = false

  if ($command == "goto" Or $command == "Goto") And ($ift == "" Or stringright($ift, 1) == "t") then
    if StringLeft($r[1], 1) == "'" or StringLeft($r[1], 1) == '"'  then ; 1 is text
      $tempread1 = StringTrimLeft(StringTrimRight($r[1], 1), 1)
    elseif StringIsDigit(Stringleft($r[1], 1)) == 1 then ; 1 is number
      $tempread1 = $r[1]
    else ; its code so we're going to execute it.
      $execute1 = true
    endif
    if Ubound($r) == 4 then
      if StringLeft($r[2], 1) == "'" or StringLeft($r[2], 1) == '"'  then ; 2 is text
        $tempread2 = StringTrimLeft(StringTrimRight($r[2], 1), 1)
      elseif StringIsDigit(Stringleft($r[2], 1)) == 1 then ; 2 is number
        $tempread2 = $r[2]
      else ; its code so we're going to execute it.
        $execute2 = true
      endif

      if StringLeft($r[3], 1) == "'" or StringLeft($r[3], 1) == '"'  then ; 3 is text
        $tempread3 = StringTrimLeft(StringTrimRight($r[3], 1), 1)
      elseif StringIsDigit(Stringleft($r[3], 1)) == 1 then ; 3 is number
        $tempread3 = $r[3]
      else ; its code so we're going to execute it.
        $execute3 = true
      endif

      if $execute1 And $execute2 And $execute3 then
        $return = ExecuteProc(execute($tempread1), execute($tempread2), execute($tempread3))
      elseif $execute1 And $execute2 then
        $return = ExecuteProc(execute($tempread1), execute($tempread2),         $tempread3 )
      elseif $execute1 And $execute3 then
        $return = ExecuteProc(execute($tempread1),         $tempread2 , execute($tempread3))
      elseif $execute2 And $execute3 then
        $return = ExecuteProc(        $tempread1 , execute($tempread2), execute($tempread3))
      elseif $execute1 then
        $return = ExecuteProc(execute($tempread1),         $tempread2 ,         $tempread3 )
      elseif $execute2 then
        $return = ExecuteProc(        $tempread1 , execute($tempread2),         $tempread3 )
      elseif $execute3 then
        $return = ExecuteProc(        $tempread1 ,         $tempread2 , execute($tempread3))
      else
        $return = ExecuteProc(        $tempread1 ,         $tempread2 ,         $tempread3 )
      endif
    elseif Ubound($r) == 3 then
      if StringLeft($r[2], 1) == "'" or StringLeft($r[2], 1) == '"'  then ; 2 is text
        $tempread2 = StringTrimLeft(StringTrimRight($r[2], 1), 1)
      elseif StringIsDigit(Stringleft($r[2], 1)) == 1 then ; 2 is number
        $tempread2 = $r[2]
      else ; its code so we're going to execute it.
        $execute2 = true
      endif

      elseif $execute1 And $execute2 then
        $return = ExecuteProc(execute($tempread1), execute($tempread2))
      elseif $execute1 then
        $return = ExecuteProc(execute($tempread1),         $tempread2 )
      elseif $execute2 then
        $return = ExecuteProc(        $tempread1 , execute($tempread2))
      else
        $return = ExecuteProc(        $tempread1 ,         $tempread2 )
      endif
    elseif Ubound($r) == 2 then
      if $execute1 then
        $return = ExecuteProc(execute($tempread1))
      else
        $return = ExecuteProc(        $tempread1 )
      endif
    endif
  elseif ($command == "set " Or $command == "Set ") And ($ift == "" Or stringright($ift, 1) == "t") then
    if UBound($r) == 3 then
      if StringLeft($r[1], 1) == "'" or StringLeft($r[1], 1) == '"'  then ; 1 is text
        $tempread1 = StringTrimLeft(StringTrimRight($r[1], 1), 1)
      elseif StringIsDigit(Stringleft($r[1], 1)) == 1 then ; 1 is number
        $tempread1 = $r[1]
      else ; its code so we're going to execute it.
        $execute1 = true
      endif

      if StringLeft($r[2], 1) == "'" or StringLeft($r[2], 1) == '"'  then ; 2 is text
        $tempread2 = StringTrimLeft(StringTrimRight($r[2], 1), 1)
      elseif StringIsDigit(Stringleft($r[2], 1)) == 1 then ; 2 is number
        $tempread2 = $r[2]
      else ; its code so we're going to execute it.
        $execute2 = true
      endif

      if $execute1 And $execute2 then
        $v[execute($tempread1)] = execute($tempread2)
      elseif $execute1 then
        $v[execute($tempread1)] = $tempread2
      elseif $execute2 then
        $v[$tempread1] = execute($tempread2)
      else
        $v[$tempread1] = $tempread2
      endif
    elseif ubound($r) > 3 then
      for $temp = 2 to ubound($r)-1
        $a[$r[1]][$temp-2] = $r[$temp]
      next
    endif
  elseif ($command == "loop" Or $command == "Loop") And ($ift == "" Or stringright($ift, 1) == "t") then
    ExecuteLoop($r[1], $arg1, $arg2, $temp, $temp1, $return, $command)
  elseif ($command == "endl" or $command == "Endl") And ($ift == "" Or stringright($ift, 1) == "t") then
    return 300
  elseif ($command == "bklp" or $command == "Bklp") And ($ift == "" Or stringright($ift, 1) == "t") then
    ;$ift = ""
    return "bklp"
  elseif $command == "ift " Or $command == "Ift " then
    if $ift == "" Or stringright($ift, 1) == "t" then
      if execute(stringtrimleft($read, 4)) then
        $ift = $ift & "t"
        $embeddedif = $embeddedif + 1
      else
        $ift = $ift & "f"
      endif
    endif
  elseif $command == "elif" Or $command == "Elif" then
    if $ift == "f" Or stringright($ift, 2) == "tf" then
      if execute(stringtrimleft($read, 4)) then
        $ift = stringtrimright($ift, 1)
        $ift = $ift & "t"
        $embeddedif = $embeddedif + 1
      else
        $ift = stringtrimright($ift, 1)
        $ift = $ift & "f"
      endif
    endif
  elseif $command == "else" Or $command == "Else" then
    if $ift == "f" Or stringright($ift, 2) == "tf" then
      $ift = stringtrimright($ift, 1)
      $ift = $ift & "t"
      $embeddedif = $embeddedif + 1
    else
      $ift = stringtrimright($ift, 1)
      $ift = $ift & "f"
    endif
  elseif ($command == "endi" Or $command == "Endi") then
    if $ift == "" Or stringright($ift, 1) == "t" then
      $ift = stringtrimright($ift, 1)
      $embeddedif = $embeddedif - 1
    elseif stringright($ift, 1) == "f" then
      $ift = stringtrimright($ift, 1)
      $embeddedif = $embeddedif - 1
    endif
  elseif ($command == "endp" Or $command == "Endp") And ($ift == "" Or stringright($ift, 1) == "t")then
    if Ubound($r) == 2 then
      if stringleft($r[1], 1) == "$" then
        $return = ExecuteProc(execute($r[1]))
      else
        $return = $r[1]
      endif
    else
      $return = ""
    endif
    $pcount =300
  elseif  ($read == "exit" Or $read == "Exit") And ($ift == "" Or stringright($ift, 1) == "t") then
    Exit
  else
    if  $ift == "" Or stringright($ift, 1) == "t" then
      Execute($read)
    endif
  endif

EndFunc

ImportPlugin()














;METHOD 3 (special Raw Execute)
;at least 3 arrays:
  ;1. proc code, arguments of procs = 2d array p[]
  ;2. variables (public)  g[]
  ;3. variables (private) v[]

;this script loads the entire plugin.
;as it loads it it fills up the arrays.
;no returns, args
;everything is separated by spaces
;encoding of Functions:
  ;proc 0          - tells you which i to put it in.
    ;args 1 2     - array 1 1-99
    ;              - array 1 first,
  ;endp            - none
;encoding calling functions
  ;goto 2          - start loading each line from p[2] into execution
;encoding of variables:
  ;set 1 [code]       - v[1] = Execute($restofline)
  ;set 1 puts 2       - v[1] = v[2]
;we may use set as setv for arrays and let them use assign for regular variables
;so first we analyze it to separate it out,
;then the very last line of the code should be only number
;thats when we switch over to run mode
;and starting with the numbered proc we being to execute each line of code.

;limitations:
  ; we could make arrays of 1000 or something like a1-10
  ; no includes
  ; no switches or anything else other than If statement.
  ; clunky. but basically func becomes proc args call becomes goto and local becomes set, while becomes loop, if becomes ift

;how to prepare plugins
  ;1. create a plugin script
  ;2. encrypt the data, replace code
  ;3. encryptfile, put in the plugins folder in scriptdir.

;plugin requirements:
  ;1. cannot have a function called "ImportPlugin"
  ;2. cannot have a function called "ExecutePlugin"
  ;3. cannot have a variable called "$__R__"
  ;4. cannot have a variable called "$__READ__"
  ;5. you must load everything into Memory before you being to execute.
  ;6. Your plugin cannot have more than 30k lines of code.
  ;7. cannot #include anything.
  ;8. cannot assign variables the normal way. you must use Assign("message", "world") (Assign, Call, Eval)
  ;9. convention suggests you use RMPlugin_ at the beginning of all function and variables in order to avoid duplicates because all the includes have to be

That's the actual script that acts as the plugin-executor.

I basically had to recreate flow-control inside the context of the autoit flow-control. Which means I had to make a sudo-language. 

Hobby: masochist.  

Here's an example script I created to show how it works. 

 

;how to set a hotkey key procnumber - must be first thing you do.
hkps {END} 3

;proc 0 is the natural entry point to the program.
;If you want it to constantly run, and wait for user hotkey then make proc 0 look like this:
;proc 0
;  loop
;  endl
;endp
;here's a sudo-function. only numbers (as the name) allowed. No need to specify arguments
proc 0
  ; this how you make comment
  ;

  ; make a call:
  goto 1

  ; reference a variable
  msgbox(64,"01","hello " & $v[1] )

  ; reference elements in an array
  msgbox(64,"01","hello " & $a[1][1] & $a[1][2] & $a[1][3] )

  goto 4

;end sudo function
endp

proc 1

  ; make a variable - use number as variable name
  set 1 "world"
  msgbox(64,"1","hello " & $v[1])

  ; variable substitution available on name or value.
  set 9 1
  set $v[9] "world!"
  msgbox(64,"1","hello " & $v[1])

  ; make an array - substitution not not allowed when creating these, its litteral
  set 1 "a" b "c" d "e" f

  ; make some regular autoit code
  msgbox(64,"1","hello world")

  ; 2 max arguments allowed. arguments only allow single words or numbers or variables
  goto 2 hello $v[1]

  ; how to access the return
  msgbox(64,"1-returned",$return)
Endp

proc 2 args are ignored if you write them in here.

  ; here's how to use args, 1 or 2 args allowed
  msgbox(64, "2", $arg1 & " " & $arg2)

  ; if you want to return a value simply add it onto the end of this line
Endp goodbyeworld


proc 3 called from hotkey

  msgbox(64, "3", "called from hotkey")

Endp

code outside procs are ignored, like comments


proc 4 if statements are ift statments NO then

  ift $v[1] == "hello"
    msgbox(64,"4","this is false and wont be executed!")
  elif $v[1] == "world"
    msgbox(64,"4","hello ift statement! this is elif")
  endi

  ift $v[1] == "goodbye"
    msgbox(64,"4","this is false and wont be executed!")
  else
    msgbox(64,"4","Hello else statement!")
  endi

  msgbox(64,"4","This code is not in an if statement.")

  set 1 0

  goto 5

endp


proc 5 for small loops recursion should work fine

  ift $v[1] == 3
    msgbox(64,"5","done with loop! please press the END key after you press ok. " & $v[1])

    ;wait so we can test the hotkey command
    sleep(5000)

    goto 6
  else
    msgbox(64,"5",$v[1])
    set 1 $v[1]+1
    goto 5
  endi

endp



proc 6 but for large loops or embedded loops "loop" might work best.

  set 2 0

  loop
    set 2 $v[2]+1
    tooltip($v[2])
    sleep(1000)
    ift $v[2] >= 2
      bklp
    endi
  endl

  set 3 0
  set 4 0

  loop
    loop
      set 3 $v[3]+1
      tooltip($v[3])
      sleep(1000)
      ift $v[3] >= 2
        bklp
      endi
    endl
    set 4 $v[4]+1
    tooltip($v[4])
    sleep(1000)
    ift $v[4] >= 2
      bklp
    endi
  endl

  msgbox(64,"6","This concludes our tour of the au3p language!")

endp

 

Edited by LegitStack

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...