lua-users home
lua-l archive

[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\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 ... )