[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Can LPeg parse PNG?
- From: Sean Conner <sean@...>
- Date: Fri, 9 Dec 2016 23:56:00 -0500
It was thus said that the Great Sean Conner once stated:
> It was thus said that the Great KHMan once stated:
> > On 12/10/2016 9:46 AM, Duncan Cross wrote:
> > >On Sat, Dec 10, 2016 at 12:10 AM, Soni L. wrote:
> > >>I was told PNG is a regular language, in the sense that you can validate
> > >>any
> > >>PNG chunk with a VERY VERY VERY LONG regex.
Well, I reread the original "challenge" and okay, I need to validate the
four critical chunks using LPeg. Okay, not an issue. Change:
local type = #-P"IEND"
* type1 * type2 * type3 * type4
* Cg(Cmt(Cc(true),function(subject,pos,_)
return pos,subject:sub(pos - 4,pos - 1)
end),'type')
local png = header * Ct(Ct(IHDR) * (Ct(PLTE + chunk))^1 * Ct(IEND))
then add the following to parse IHDR, PLTE and IEND:
local bits = P"\1" * Cc( 1)
+ P"\2" * Cc( 2)
+ P"\4" * Cc( 4)
+ P"\8" * Cc( 8)
+ P"\16" * Cc(16)
local color = P"\0" * Cc "greyscale"
+ P"\2" * Cc "RGB"
+ P"\3" * Cc "palette"
+ P"\4" * Cc "greyscale-alpha"
+ P"\6" * Cc "RGB-alpha"
local compression = P"\0" * Cc "deflate"
local filter = P"\0" * Cc "adaptive"
local interlace = P"\0" * Cc "none"
+ P"\1" * Cc "Adam7"
local IHDR = P"\0\0\0\13IHDR"
* Cg(Cc "IHDR",'type')
* Cg(Cc(true),'critical')
* Cg(Cc(false),'private')
* Cg(Cc(false),'ignore')
* Cg(Cc(false),'safecopy')
* Cg(value4,'width')
* Cg(value4,'height')
* Cg(bits,'bits')
* Cg(color,'color')
* Cg(compression,'compression')
* Cg(filter,'filter')
* Cg(interlace,'interlace')
* Cg(value4,'crc')
* Cmt(
Cb('color') * Cb('bits') * Cb('crc'),
function(subject,pos,color,bits,crc)
-- check crc, skipped for now
if color == 'greyscale' then
return pos
end
if color == 'RGB' and bits == 8 or bits == 16 then
return pos
end
if color == 'palette' and bits ~= 16 then
return pos
end
if color == 'greyscale-alpha'
and bits == 8 or bits == 16 then
return pos
end
if color == 'RGB-alpha'
and bits == 8 or bits == 16 then
return pos
end
end
)
local PLTE = Cg(value,'length')
* Cg(P"PLTE",'type')
* Cg(data,'data')
* Cg(value,'crc')
* Cmt(
Cb('length') * Cb('crc'),
function(subject,pos,length,data,crc)
if length % 3 ~= 0 then
return nil
end
-- --------------------------------------------
-- pull the colortype and bits right out of the
-- data stream. It's there in the subject,
-- might as well take advantage of it being
-- here.
-- --------------------------------------------
local colortype = subject:sub(26):byte()
local bits = subject:sub(25):byte()
if colortype == 0 or colortype == 4 then
return nil
end
if length // 3 > 2^bits then
return nil
end
return pos
end
)
local IEND = P"\0\0\0\0IEND"
* Cg(Cc "IEND",'type')
* Cg(Cc(true),'critical')
* Cg(Cc(false),'private')
* Cg(Cc(false),'ignore')
* Cg(Cc(false),'safecopy')
* Cg(value4,'crc')
There's not much to validating IDAT---you can either decompress the data,
or you can't. But hey, there's enough here to add explicit code for IDAT.
-spc (There, enough LPeg for the day ... )