InTesting

Junkstring Functions

Aug 4th, 2021 (edited)
987
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 15.54 KB | None | 0 0
  1. --[[
  2.     Junkstring functions
  3.  
  4. CREDITS:
  5.    
  6.      + Original Plugin (https://www.roblox.com/library/2744793551/)
  7.         by Autterfly (https://www.roblox.com/users/70540486/profile/)
  8.    
  9.      + Moonsec junkstring functions by yours truly
  10.    
  11.     Don't erase the credits. It's uncool. :(
  12.    
  13.     To look over documentation, ctrl + f "Noted Function 1"
  14.    
  15.     Note:
  16.         Doesn't include some escape sequences in longstrings
  17.    
  18.     Updates (M/D/Y):
  19.    
  20.     8/10/21
  21.       + PSU junkstring
  22.    
  23.     8/10/21 >
  24.       + Moonsec junkstring functions
  25. --]]
  26.  
  27. -- Variables
  28. --  tables
  29. local JunkstringFunctions = {}
  30. local JunkstringOptions = {}
  31.  
  32. --  noted
  33. local WhiteChars,CharacterForEscape,AllIdentStartChars,AllIdentChars,Keywords,Digits,HexDigits,
  34. BinaryDigits,EqualSymbols,CompoundAssignments,Symbols
  35.  
  36.     = unpack{};
  37.  
  38. -- functions
  39.  
  40. ----------------------------------------------------------------------------------------------------
  41. -- > Autterfly
  42. ----------------------------------------------------------------------------------------------------
  43. local function CreateLuaTokenStream(text)
  44.     -- Tracking for the current position in the buffer, and
  45.     -- the current line / character we are on.
  46.     local p = 1
  47.  
  48.     -- Output buffer for tokens
  49.     local tokenBuffer = {}
  50.  
  51.     -- Get a character, or '' if at eof
  52.     local function look(n)
  53.         n = p + (n or 0)
  54.         return text:sub(n, n)
  55.     end
  56.     local function get()
  57.         local c = text:sub(p, p)
  58.         p = p + 1
  59.         return c
  60.     end
  61.  
  62.     -- Error
  63.     local olderr = error
  64.     local function error(str)
  65.         local q = 1
  66.         local line = 1
  67.         local char = 1
  68.         while q <= p do
  69.             if text:sub(q, q) == '\n' then
  70.                 line = line + 1
  71.                 char = 1
  72.             else
  73.                 char = char + 1
  74.             end
  75.             q = q + 1
  76.         end
  77.         for _, token in pairs(tokenBuffer) do
  78.             print(token.Type.."<"..token.Source..">")
  79.         end
  80.         olderr("file<"..line..":"..char..">: "..str)
  81.     end
  82.  
  83.     -- Consume a long data with equals count of `eqcount'
  84.     local function longdata(eqcount)
  85.         while true do
  86.             local c = get()
  87.             if c == '' then
  88.                 error("Unfinished long string.")
  89.             elseif c == ']' then
  90.                 local done = true -- Until contested
  91.                 for _ = 1, eqcount do
  92.                     if look() == '=' then
  93.                         p = p + 1
  94.                     else
  95.                         done = false
  96.                         break
  97.                     end
  98.                 end
  99.                 if done and get() == ']' then
  100.                     return
  101.                 end
  102.             end
  103.         end
  104.     end
  105.  
  106.     -- Get the opening part for a long data `[` `=`* `[`
  107.     -- Precondition: The first `[` has been consumed
  108.     -- Return: nil or the equals count
  109.     local function getopen()
  110.         local startp = p
  111.         while look() == '=' do
  112.             p = p + 1
  113.         end
  114.         if look() == '[' then
  115.             p = p + 1
  116.             return p - startp - 1
  117.         else
  118.             p = startp
  119.             return nil
  120.         end
  121.     end
  122.  
  123.     -- Add token
  124.     local whiteStart = 1
  125.     local tokenStart = 1
  126.     local function token(type)
  127.         local tk = {
  128.             Type = type;
  129.             LeadingWhite = text:sub(whiteStart, tokenStart-1);
  130.             Source = text:sub(tokenStart, p-1);
  131.         }
  132.         table.insert(tokenBuffer, tk)
  133.         whiteStart = p
  134.         tokenStart = p
  135.         return tk
  136.     end
  137.  
  138.     -- Parse tokens loop
  139.     while true do
  140.         -- Mark the whitespace start
  141.         whiteStart = p
  142.  
  143.         -- Get the leading whitespace + comments
  144.         while true do
  145.             local c = look()
  146.             if c == '' then
  147.                 break
  148.             elseif c == '-' then
  149.                 if look(1) == '-' then
  150.                     p = p + 2
  151.                     -- Consume comment body
  152.                     if look() == '[' then
  153.                         p = p + 1
  154.                         local eqcount = getopen()
  155.                         if eqcount then
  156.                             -- Long comment body
  157.                             longdata(eqcount)
  158.                         else
  159.                             -- Normal comment body
  160.                             while true do
  161.                                 local c2 = get()
  162.                                 if c2 == '' or c2 == '\n' then
  163.                                     break
  164.                                 end
  165.                             end
  166.                         end
  167.                     else
  168.                         -- Normal comment body
  169.                         while true do
  170.                             local c2 = get()
  171.                             if c2 == '' or c2 == '\n' then
  172.                                 break
  173.                             end
  174.                         end
  175.                     end
  176.                 else
  177.                     break
  178.                 end
  179.             elseif WhiteChars[c] then
  180.                 p = p + 1
  181.             else
  182.                 break
  183.             end
  184.         end
  185.         -- local leadingWhite = text:sub(whiteStart, p-1) -- unused(?)
  186.  
  187.         -- Mark the token start
  188.         tokenStart = p
  189.  
  190.         -- Switch on token type
  191.         local c1 = get()
  192.         if c1 == '' then
  193.             -- End of file
  194.             token('Eof')
  195.             break
  196.         elseif c1 == '\'' or c1 == '\"' then
  197.             -- String constant
  198.             while true do
  199.                 local c2 = get()
  200.                 if c2 == '\\' then
  201.                     local c3 = get()
  202.  
  203.                     if tonumber(c3) or c3:lower()=='x' then -- Reru fix
  204.                         for _ = 1, 2 do
  205.                             c3 = c3 .. look()
  206.  
  207.                             local num = tonumber('0'..c3)
  208.  
  209.                             if tonumber(c3)or num then
  210.                                 get()
  211.                                 if (tonumber(c3) or num) > 255 then
  212.                                     error("Non representable character escape `" .. c3 .. "`.")
  213.                                 end
  214.                             else
  215.                                 break
  216.                             end
  217.                         end
  218.                     else
  219.                         local esc = CharacterForEscape[c3]
  220.                         if not esc then
  221.                             error("Invalid Escape Sequence `"..c3.."`.")
  222.                         end
  223.                     end
  224.                 elseif c2 == c1 then
  225.                     break
  226.                 end
  227.             end
  228.             token('String')
  229.         elseif AllIdentStartChars[c1] then
  230.             -- Ident or Keyword
  231.             while AllIdentChars[look()] do
  232.                 p = p + 1
  233.             end
  234.             if Keywords[text:sub(tokenStart, p-1)] then
  235.                 token('Keyword')
  236.             else
  237.                 token('Ident')
  238.             end
  239.         elseif Digits[c1] or (c1 == '.' and Digits[look()]) then
  240.             -- Number
  241.  
  242.             local HexLuaUNumber = text:match('[_]+[xX][%x_]+',p)
  243.             local TouchedX = look():lower() == 'x'
  244.  
  245.             local BinLuaUNumber = text:match('[_]+[bB][01_]+',p)
  246.             local TouchedB = look():lower() == 'b'
  247.  
  248.             -- note: may need to do this better, code below look similar
  249.  
  250.             if c1 == '0' and (TouchedX or HexLuaUNumber) then
  251.  
  252.                 p = p + 1
  253.                 -- Hex number
  254.                 while HexDigits[look()]or
  255.                     look()=='_'or
  256.                     (not TouchedX and look():lower()=='x')do
  257.  
  258.  
  259.                     if(not TouchedX and look():lower()=='x')then
  260.                         TouchedX = true
  261.                     end
  262.  
  263.                     p = p + 1
  264.                 end
  265.             elseif c1 == '0' and (TouchedB or BinLuaUNumber) then
  266.  
  267.                 p = p + 1
  268.                 -- bin number
  269.                 while BinaryDigits[look()]or
  270.                     look()=='_'or
  271.                     (not TouchedB and look():lower()=='b')do
  272.  
  273.  
  274.                     if(not TouchedB and look():lower()=='b')then
  275.                         TouchedB = true
  276.                     end
  277.  
  278.                     p = p + 1
  279.                 end
  280.             else
  281.                 -- Normal Number + weird luau number with underscore
  282.                 while Digits[look()]or look()=='_'do
  283.                     p = p + 1
  284.                 end
  285.                 if look() == '.' then
  286.                     -- With decimal point
  287.                     p = p + 1
  288.                     while Digits[look()]or look()=='_' do
  289.                         p = p + 1
  290.                     end
  291.                 end
  292.                 if look():lower() == 'e' then
  293.                     -- With exponent
  294.                     p = p + 1
  295.                     if look() == '-' then
  296.                         p = p + 1
  297.                     end
  298.                     while Digits[look()]or look()=='_' do
  299.                         p = p + 1
  300.                     end
  301.                 end
  302.             end
  303.  
  304.  
  305.             token('Number')
  306.         elseif c1 == '[' then
  307.             -- '[' Symbol or Long String
  308.             local eqCount = getopen()
  309.             if eqCount then
  310.                 -- Long string
  311.                 longdata(eqCount)
  312.                 token('String')
  313.             else
  314.                 -- Symbol
  315.                 token('Symbol')
  316.             end
  317.         elseif c1 == '.' then
  318.             -- Greedily consume up to 3 `.` for . / .. / ... tokens + compound operator ..=
  319.             if look() == '.' then
  320.                 get()
  321.                 if ({
  322.                     ['.'] = true;
  323.                     ['='] = true
  324.                     })[look()]then
  325.                     get()
  326.                 end
  327.             end
  328.             token('Symbol')
  329.         elseif EqualSymbols[c1] then
  330.             if look() == '=' then
  331.                 p = p + 1
  332.             end
  333.             token('Symbol')
  334.         elseif CompoundAssignments[c1 .. look()] then
  335.             p = p + 1
  336.  
  337.             token('Symbol')
  338.         elseif Symbols[c1] then
  339.             token('Symbol')
  340.         else
  341.             error("Bad symbol `"..c1.."` in source.")
  342.         end
  343.     end
  344.  
  345.  
  346.     return tokenBuffer
  347. end
  348.  
  349. ----------------------------------------------------------------------------------------------------
  350. -- > Yours truly
  351. ----------------------------------------------------------------------------------------------------
  352. --  1l
  353. function FlipTable(t)local a = {}for i,v in next,t do a[v] = i end return a end
  354. function lookifycharactersfromstring(a)return FlipTable(a:split'')end
  355. function TableRandom(t)return t[math.random(1,#t)]end
  356.  
  357. --  general
  358. function IsDictionary(t)
  359.     if not(type(t)=='table'and#t==0)then return end
  360.  
  361.     for i,v in next,t do
  362.         if type(i)=='string'then return true end
  363.     end
  364. end
  365.  
  366. function MergeTables(...)
  367.     local a = {}
  368.     for _,t in next,{...}do
  369.         for _,v in next,t do
  370.             table.insert(a,v)
  371.         end
  372.     end
  373.     return a
  374. end
  375.  
  376. function GetCharactersInRange(a,b)
  377.     local c,d = (a..b):byte(1,2)
  378.     local t = {}
  379.     for i = c, d do table.insert(t, string.char(i))end
  380.     return t
  381. end
  382.  
  383. function GetCharactersInRangeFromString(a)return GetCharactersInRange(unpack(a:split''))end
  384.  
  385. function GetCharactersInRangeFromLongerString(a,b)
  386.     local t = {}
  387.     if a then
  388.         for c = 1,#a/2 do
  389.             local pos = c * 2
  390.  
  391.             local d = a:sub(pos-1,pos)
  392.             table.insert(t,GetCharactersInRangeFromString(d))
  393.         end
  394.     end
  395.     if b then
  396.         table.insert(t,b:split'')
  397.     end
  398.  
  399.     return FlipTable(MergeTables(unpack(t)))
  400. end
  401.  
  402. function IsAString(str)
  403.     for _,tk in next,{"'",'"',{'[[',']]'}}do
  404.         tk = type(tk)=='string'and{tk,tk}or tk
  405.  
  406.         local prefix,suffix = unpack(tk)
  407.  
  408.         local checkprefix,checksuffix =
  409.             str:sub(1,#prefix) == prefix,
  410.             str:sub(#str - #suffix + 1) == suffix
  411.  
  412.         if checkprefix and checksuffix then
  413.             return str:sub(#prefix + 1,#str - #suffix)
  414.         end
  415.     end
  416. end
  417.  
  418. function LuaStringify(s)
  419.     return '\'' ..
  420.         s:gsub('.',{
  421.             ['\n'] = '\\n';
  422.             ['\\'] = '\\\\';
  423.             ['\t'] = '\\t';
  424.             ["'"] = "\'"
  425.         }) ..
  426.         '\''
  427. end
  428.  
  429. function DeluaStringify(s)
  430.     local char1 = s:sub(1,1)
  431.     local char2 = s:sub(#s)
  432.  
  433.     local st,en = 2,#s-1
  434.  
  435.     if char1=='['then
  436.         st+=1
  437.         en-=1
  438.         char1 = '%]'
  439.     end
  440.  
  441.     s = s:sub(st,en)
  442.     local b = FlipTable{
  443.         ['\n'] = '\\n';
  444.         ['\\'] = '\\\\';
  445.         ['\t'] = '\\t';
  446.         [char2] = "\\"..char2
  447.     }
  448.  
  449.     return s:gsub('[\\][n\\t'.. char2 .. ']',b)
  450. end
  451.  
  452. --  submain
  453. function GetBuffersSource(Buffer)
  454.     local t = {}
  455.     for _,a in next,Buffer do
  456.         if a.LeadingWhite~=''then
  457.             table.insert(t,a.LeadingWhite)
  458.         end
  459.  
  460.         table.insert(t,a.Source)
  461.     end
  462.     return t
  463. end
  464.  
  465. function TableSourceReplace(tblesc,index,option)
  466.     local value = tblesc[index]
  467.     local str = DeluaStringify(value)
  468.  
  469.     local ExpectedString = type(option.Junkstrings)=='string'and LuaStringify(option.Junkstrings:rep(#str))
  470.  
  471.     if not ExpectedString then
  472.         local Junkstring = TableRandom(option.Junkstrings)
  473.         local newstr = LuaStringify(Junkstring)
  474.  
  475.         local lendiff =  #str - #Junkstring
  476.         print(str,Junkstring,lendiff)
  477.  
  478.         local symb = math.sign(lendiff)~=-1 and'+'or'-'
  479.  
  480.         if symb=='-'then
  481.             lendiff = tostring(lendiff):sub(2)
  482.         end
  483.  
  484.         ExpectedString = newstr .. symb .. lendiff
  485.     end
  486.  
  487.     tblesc[index] = ExpectedString
  488. end
  489.  
  490. function TableSourceCompress(tblesc,index)
  491.     local val = DeluaStringify(tblesc[index])
  492.     tblesc[index - 1] = ''
  493.     tblesc[index] = #val
  494. end
  495.  
  496. --  main
  497. --[[
  498. Noted Function 1
  499.  
  500. Arguments:
  501.     str: Source Code
  502.     dict: Options + arguments
  503.         Refer to the chart below
  504. ----------------------------------------------------------------------------------------------------
  505. Index (string) | Value Type | Requirement (Mandatory (M)) | Description
  506.                |            |   or Value from Index Type  |
  507. ----------------------------------------------------------------------------------------------------
  508. Type           | String     | M                           | Determines result:
  509.                |            |                             |  + Replace: Replaces current junkstrings
  510.                |            |                             |       with a random junkstring from an
  511.                |            |                             |       array or a replacement character
  512.                |            |                             |       with the same length
  513.                |            |                             |  + Compress: Removes all junkstrings and
  514.                |            |                             |       replaces them with their length
  515. Junkstrings    | Array      | Replace                     | Array of junkstrings, chosesn at random
  516.                |            |                             |    per iteration
  517.                | String     |                             | Used for replacing junkstrings of those
  518.                |            |                             |    of the same length, this string is
  519.                |            |                             |    supposed to be one character long, if
  520.                |            |                             |    the string is more than one character
  521.                |            |                             |    long, then the first character will
  522.                |            |                             |    be used
  523. ----------------------------------------------------------------------------------------------------
  524. --]]
  525. function ManageMoonsecSource(Source,Option)
  526.     assert(
  527.         type(Source)=='string'and
  528.             IsDictionary(Option)and
  529.             type(Option.Type)=='string'and
  530.             ({
  531.                 Replace = 1;
  532.                 Compress = 1
  533.             })[Option.Type]
  534.         ,'Bad argument'
  535.     )
  536.  
  537.     if Option.Type=='Replace'then
  538.         local Val = Option.Junkstrings
  539.         assert(
  540.             ({
  541.                 string = 1;
  542.                 table = 1
  543.             })[type(Val)],
  544.             'Bad argument'
  545.         )
  546.  
  547.         if type(Val)=='string'and#Val~=0 then
  548.             if#Val==0 then
  549.                 Val = ' '
  550.             end
  551.  
  552.             Option.Junkstrings = Val:sub(1,1)
  553.         end
  554.     end
  555.  
  556.     local Buffer = CreateLuaTokenStream(Source)
  557.     local TableSource = GetBuffersSource(Buffer)
  558.  
  559.     for i,v in next,TableSource do
  560.         if TableSource[i-1]=='#'and IsAString(v) then
  561.             JunkstringOptions[Option.Type](TableSource,i,Option)
  562.         end
  563.     end
  564.  
  565.     return table.concat(TableSource)
  566. end
  567.  
  568. function ManagePSUSource(Source,Option)
  569.     assert(
  570.         type(Source)=='string'and
  571.             IsDictionary(Option)and
  572.             type(Option.Type)=='string'and
  573.             ({
  574.                 Replace = 1;
  575.                 Compress = 1
  576.             })[Option.Type]
  577.         ,'Bad argument'
  578.     )
  579.  
  580.     if Option.Type=='Replace'then
  581.         local Val = Option.Junkstrings
  582.         assert(
  583.             ({
  584.                 string = 1;
  585.                 table = 1
  586.             })[type(Val)],
  587.             'Bad argument'
  588.         )
  589.  
  590.         if type(Val)=='string'and#Val~=0 then
  591.             if#Val==0 then
  592.                 Val = ' '
  593.             end
  594.  
  595.             Option.Junkstrings = Val:sub(1,1)
  596.         end
  597.     end
  598.  
  599.     local Buffer = CreateLuaTokenStream(Source)
  600.     local TableSource = GetBuffersSource(Buffer)
  601.  
  602.  
  603.     for i,v in next,TableSource do
  604.         if TableSource[i-2]=='#'and
  605.             TableSource[i-1]=='('and
  606.             IsAString(v)and
  607.             TableSource[i+1]==')'
  608.             then
  609.            
  610.             for k,v in next,{
  611.                 '',
  612.                 '#',
  613.                 v,
  614.                 ''
  615.                 }do
  616.                
  617.            
  618.                 TableSource[i + k - 3] = v
  619.             end
  620.            
  621.             JunkstringOptions[Option.Type](TableSource,i,Option)
  622.         end
  623.     end
  624.  
  625.     return table.concat(TableSource)
  626. end
  627.  
  628.  
  629. -- assignments
  630. --  renoted
  631. do
  632.     WhiteChars,CharacterForEscape,AllIdentStartChars,AllIdentChars,Keywords,Digits,HexDigits,
  633.         BinaryDigits,EqualSymbols,CompoundAssignments,Symbols =
  634.         lookifycharactersfromstring' \n\t\r',
  635.         {
  636.             ['"'] = '"',
  637.             ['\\'] = '\\',
  638.             ['a'] = '\a',
  639.             ['b'] = '\b',
  640.             ['f'] = '\f',
  641.             ['n'] = '\n',
  642.             ['r'] = '\r',
  643.             ['t'] = '\t',
  644.             ['v'] = '\v',
  645.             ["'"] = "'"
  646.         },
  647.         GetCharactersInRangeFromLongerString('azAZ','_'),
  648.         GetCharactersInRangeFromLongerString('azAZ09','_'),
  649.         FlipTable{
  650.             'and',
  651.             'break',
  652.             'do',
  653.             'else',
  654.             'elseif',
  655.             'end',
  656.             'false',
  657.             'for',
  658.             'function',
  659.             'goto',
  660.             'if',
  661.             'in',
  662.             'local',
  663.             'nil',
  664.             'not',
  665.             'or',
  666.             'repeat',
  667.             'return',
  668.             'then',
  669.             'true',
  670.             'until',
  671.             'while'
  672.         },
  673.         GetCharactersInRangeFromLongerString'09',
  674.         GetCharactersInRangeFromLongerString'afAF09',
  675.         FlipTable(('01'):split''),
  676.         GetCharactersInRangeFromLongerString(nil,'~=><'),
  677.         FlipTable{
  678.             '+=',
  679.             '-=',
  680.             '*=',
  681.             '/=',
  682.             '%=',
  683.             '^=',
  684.             '..='
  685.         },
  686.         GetCharactersInRangeFromLongerString(nil,'+-*/^%,{}[]();#.:')
  687. end
  688. --  main
  689. JunkstringFunctions.ManageMoonsecSource = ManageMoonsecSource
  690. JunkstringFunctions.ManagePSUSource = ManagePSUSource
  691.  
  692. JunkstringOptions.Replace = TableSourceReplace
  693. JunkstringOptions.Compress = TableSourceCompress
  694.  
  695. -- return
  696. return JunkstringFunctions
Add Comment
Please, Sign In to add comment