2

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
Glupschi
  • 215
  • 1
  • 9

2 Answers2

2

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

Nifim
  • 4,758
  • 2
  • 12
  • 31
  • i understand your solution, but i have another problem. I am reading in my input from an file. So it doesnt work like this for an file. Or how can i transfer the data of an file into an string like for input ? – Glupschi Mar 16 '21 at 14:40
  • you can do this `path = "some\\path\\to\\file.txt"; local f = assert(io.open(path)); local data = f:read("*all"); f:close();` – Nifim Mar 16 '21 at 15:01
  • Actually i see you have a function in your OP for reading a whole file into a variable, `content` in the case of that function. i believe i understand, your data is not `56 30 30 31 ` but `\56\30\30\31`? – Nifim Mar 16 '21 at 15:10
  • when you say it is hexadecimal, do you mean the file contains hexadecimal values represented in ascii, so if you looked in notepad the values would be readable, or that the value are actual binary and look like gibberish if viewed in notepad? – Nifim Mar 16 '21 at 15:20
  • sorry I mean the file is actual binary and looks gibberish if viewed in notepad. you can open it with an Hex editor than it comes like the examples i showed in my question. So I am actually searching vor 'V' '0' '0' '1' in my file. Thats 0x56 0x30 0x30 0x31 when you view it in Hexadecimal – Glupschi Mar 16 '21 at 15:25
  • change `rowPrefix` to `"\56\30\30\31"` – Nifim Mar 16 '21 at 15:25
  • you have `0x00` chars in the string which can cause some issues with string functions. – Nifim Mar 16 '21 at 15:32
  • 1
    sorry forgot the `x` in those suggested changes to `rowPrefix` it should be "\x56\x30\x30\x31" – Nifim Mar 16 '21 at 15:45
2

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)
lhf
  • 70,581
  • 9
  • 108
  • 149