lua-users home
lua-l archive

Re: Can LPeg parse PNG?

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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円13円IHDR"
 * 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円0円IEND"
	 * 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 ... )

AltStyle によって変換されたページ (->オリジナル) /