lua parsing after more than one byte

Viewed 116

how can I parse an binary after more than one byte? for example:

56 30 30 31 07 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 01 45 7E 12 02 EF BF BD 00 EF BF BD 1F 56 30 30 31 01 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 02 45 24 56 30 30 31 04 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 02 45 13 00 00 00 56 30 30 31 07 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 01 45 7E 12 02 24 00 4D EF BF

I want to parse this after 0x56 0x30 0x30 0x31. How can I do this? Before every new 0x56 0x30 0x30 0x31 the old packet(string) should end.

like this:

56 30 30 31 07 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 01 45 7E 12 02 EF BF BD 00 EF BF BD 1F

56 30 30 31 01 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 02 45 24

56 30 30 31 04 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 02 45 13 00 00 00

56 30 30 31 07 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 01 45 7E 12 02 24 00 4D EF BF

I already did something simular for parsing after one byte into an table. But I can not change it into my new problem. Thats the code for parsing after one Byte 0x7E.

function print_table(tab)
print("Table:") 
for key, value in pairs(tab) do
  io.write(string.format("%02X ", value))  
end
print("\n") 
end

local function read_file(path, callback) 
local file = io.open(path, "rb") 
if not file then 
 return nil
end
local t = {} 
repeat
local str = file:read(4 * 1024)   
for c in (str or ''):gmatch('.') do  
    if c:byte() == 0x7E then 
        callback(t) -- function print_table
        t = {}
    else
        table.insert(t, c:byte())  
    end
end
until not str
file:close() 
return t 
end

local result = {}
function add_to_table_of_tables(t)
table.insert(result, t) 
end

local fileContent = read_file("file.dat", print_table)

It is important that 56 30 30 31 is as first written in the string. Thank your for your help!

I need it also with reading my input in from an file. I am reading my file like this in:

local function read_file(path) --function read_file
  local file = io.open(path, "rb") -- r read mode and b binary mode
  if not file then return nil end
  local content = file:read "*all" -- *all reads the whole file
  file:close()
  return content
end
2 Answers

You can use a gsub to replace the target substring with a single char unique to the input string, I will use \n for this example. after that you can use gmatch where it selects a run of char that are not the substituted char.

local input = [[56 30 30 31 07 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 01 45 7E 12 02 EF BF BD 00 EF BF BD 1F 56 30 30 31 01 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 02 45 24 56 30 30 31 04 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 02 45 13 00 00 00 56 30 30 31 07 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 01 45 7E 12 02 24 00 4D EF BF]]

local pattern ="([^\n]+)"
local rowPrefix = "56 30 30 31"

input = input:gsub(rowPrefix, "\n")

for row in input:gmatch(pattern) do
  print(rowPrefix .. row)
end

Output:

56 30 30 31 07 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 01 45 7E 12 02 EF BF BD 00 EF BF BD 1F 
56 30 30 31 01 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 02 45 24 
56 30 30 31 04 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 02 45 13 00 00 00 
56 30 30 31 07 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 01 45 7E 12 02 24 00 4D EF BF

Resources for more information:

Programming in Lua: 20.1 – Pattern-Matching Functions

Lua 5.3 Reference Manual: string.gmatch

Lua 5.3 Reference Manual: string.gsub

Adapt this code:

S=[[56 30 30 31 07 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 01 45 7E 12 02 EF BF BD 00 EF BF BD 1F 56 30 30 31 01 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 02 45 24 56 30 30 31 04 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 02 45 13 00 00 00 56 30 30 31 07 00 00 00 EF BF BD EF BF BD 2A 5C EF BF BD 03 01 45 7E 12 02 24 00 4D EF BF]]
H=[[56 30 30 31]]
E="\n"
S=S:gsub(H,E..H)
S:gsub(E.."([^"..E.."]+)",print)
Related