Skip to content

Instantly share code, notes, and snippets.

@joshuaflanagan
Last active August 29, 2015 14:13
Show Gist options
  • Save joshuaflanagan/a39a2df20ced14ef04d0 to your computer and use it in GitHub Desktop.
Save joshuaflanagan/a39a2df20ced14ef04d0 to your computer and use it in GitHub Desktop.
Parse PNG file
# http://www.w3.org/TR/PNG/#5DataRep
class PNGCheck
def initialize(path)
@path = path
end
def check_all!
expected_signature = [137, 80, 78, 71, 13, 10, 26, 10]
file.seek 0
signature_data = file.read(8)
raise "unable to read signature, not enough bytes. found #{signature_data}" unless signature_data.length == 8
signature = signature_data.unpack("C*")
raise "invalid signature: #{signature.inspect} expected #{expected_signature.inspect}" unless signature == expected_signature
chunks = 0
loop do
break unless process_chunk
chunks += 1
end
puts "File is valid!"
end
def process_chunk
length_data = file.read(4)
return false if length_data.nil? || length_data == ""
raise "expected 4 bytes for LENGTH, got '#{length_data}'" unless length_data.length == 4
length = length_data.unpack("N").first
type = file.read(4)
raise "expected 4 bytes for TYPE, got '#{type}'" unless type.length == 4
data = file.read(length)
raise "expected #{length} bytes for DATA, got #{data.length}" unless data.length == length
crc_data = file.read(4)
raise "expected 4 bytes for CRC, got '#{crc_data}'" unless crc_data.length == 4
crc = crc_data.unpack("N").first
crc_check = Zlib.crc32(type + data)
raise "CRC did not check" unless crc == crc_check
puts "#{type} #{length} bytes CRC: #{crc} POS: #{file.pos}"
true
end
def file
@file ||= File.open(@path, "rb")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment