-
Notifications
You must be signed in to change notification settings - Fork 171
/
png-crc-fix.go
104 lines (76 loc) · 1.86 KB
/
png-crc-fix.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package exif
// borrowed heavily from https://github.com/landaire/png-crc-fix/blob/master/main.go
import (
"bytes"
"encoding/binary"
"fmt"
"hash/crc32"
"io"
"os"
)
const chunkStartOffset = 8
const endChunk = "IEND"
type pngChunk struct {
Offset int64
Length uint32
Type [4]byte
Data []byte
CRC uint32
}
func (p pngChunk) String() string {
return fmt.Sprintf("%s@%x - %X - Valid CRC? %v", p.Type, p.Offset, p.CRC, p.CRCIsValid())
}
func (p pngChunk) Bytes() []byte {
var buffer bytes.Buffer
binary.Write(&buffer, binary.BigEndian, p.Type)
buffer.Write(p.Data)
return buffer.Bytes()
}
func (p pngChunk) CRCIsValid() bool {
return p.CRC == p.CalculateCRC()
}
func (p pngChunk) CalculateCRC() uint32 {
crcTable := crc32.MakeTable(crc32.IEEE)
return crc32.Checksum(p.Bytes(), crcTable)
}
func (p pngChunk) CRCOffset() int64 {
return p.Offset + int64(8+p.Length)
}
func readPNGChunks(reader io.ReadSeeker) []pngChunk {
chunks := []pngChunk{}
reader.Seek(chunkStartOffset, os.SEEK_SET)
readChunk := func() (*pngChunk, error) {
var chunk pngChunk
chunk.Offset, _ = reader.Seek(0, os.SEEK_CUR)
binary.Read(reader, binary.BigEndian, &chunk.Length)
chunk.Data = make([]byte, chunk.Length)
err := binary.Read(reader, binary.BigEndian, &chunk.Type)
if err != nil {
goto read_error
}
if read, err := reader.Read(chunk.Data); read == 0 || err != nil {
goto read_error
}
err = binary.Read(reader, binary.BigEndian, &chunk.CRC)
if err != nil {
goto read_error
}
return &chunk, nil
read_error:
return nil, fmt.Errorf("Read error")
}
chunk, err := readChunk()
if err != nil {
return chunks
}
chunks = append(chunks, *chunk)
// Read the first chunk
for string(chunks[len(chunks)-1].Type[:]) != endChunk {
chunk, err := readChunk()
if err != nil {
break
}
chunks = append(chunks, *chunk)
}
return chunks
}