Skip to content

Instantly share code, notes, and snippets.

@pokutuna
Created June 17, 2023 09:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pokutuna/30724e66c002247595dae803e798511f to your computer and use it in GitHub Desktop.
Save pokutuna/30724e66c002247595dae803e798511f to your computer and use it in GitHub Desktop.
package main
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"log"
"os"
)
// Block
// (4) length
// (4) type
// (n) data
// (4) CRC
func readNextBlock(f *os.File) (string, []byte, error) {
var chunkLen uint32
var chunkType [4]byte
if err := binary.Read(f, binary.BigEndian, &chunkLen); err != nil {
return "", nil, err
}
if err := binary.Read(f, binary.BigEndian, &chunkType); err != nil {
return "", nil, err
}
data := make([]byte, chunkLen)
if err := binary.Read(f, binary.BigEndian, &data); err != nil {
return "", nil, err
}
f.Seek(4, os.SEEK_CUR) // skip CRC
return string(chunkType[:]), data, nil
}
func readToNextNull(r io.ReadSeeker) ([]byte, error) {
buf := []byte{}
b := make([]byte, 1)
for {
_, err := r.Read(b)
if err != nil {
if err == io.EOF {
return buf, nil
}
if err != nil {
return nil, err
}
}
if b[0] == 0x00 {
return buf, nil
}
buf = append(buf, b[0])
}
}
func main() {
f, err := os.Open("./badge.png")
if err != nil {
log.Fatal(err)
}
defer f.Close()
// check png header
var header [8]byte
if err := binary.Read(f, binary.BigEndian, &header); err != nil {
log.Fatal(err)
}
pngHeader := []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a}
if !bytes.Equal(header[:], pngHeader) {
log.Fatal("Not a PNG file")
}
var itxt *bytes.Reader
// check block & find itxt openbadges chunk
for {
t, data, err := readNextBlock(f)
if err != nil {
log.Fatal(err)
}
if t == "iTXt" {
itxt = bytes.NewReader(data)
kw, err := readToNextNull(itxt)
if err != nil {
log.Fatal(err)
}
if bytes.Compare(kw, []byte("openbadges")) == 0 {
break
}
}
}
// skip compression
itxt.Seek(1, os.SEEK_CUR)
// skip compression format
itxt.Seek(1, os.SEEK_CUR)
// skip language tag
readToNextNull(itxt)
// skip translated keyword
readToNextNull(itxt)
text, err := readToNextNull(itxt)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", string(text))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment