Source file
src/image/format.go
1
2
3
4
5 package image
6
7 import (
8 "bufio"
9 "errors"
10 "io"
11 "sync"
12 "sync/atomic"
13 )
14
15
16 var ErrFormat = errors.New("image: unknown format")
17
18
19 type format struct {
20 name, magic string
21 decode func(io.Reader) (Image, error)
22 decodeConfig func(io.Reader) (Config, error)
23 }
24
25
26 var (
27 formatsMu sync.Mutex
28 atomicFormats atomic.Value
29 )
30
31
32
33
34
35
36
37 func RegisterFormat(name, magic string, decode func(io.Reader) (Image, error), decodeConfig func(io.Reader) (Config, error)) {
38 formatsMu.Lock()
39 formats, _ := atomicFormats.Load().([]format)
40 atomicFormats.Store(append(formats, format{name, magic, decode, decodeConfig}))
41 formatsMu.Unlock()
42 }
43
44
45 type reader interface {
46 io.Reader
47 Peek(int) ([]byte, error)
48 }
49
50
51 func asReader(r io.Reader) reader {
52 if rr, ok := r.(reader); ok {
53 return rr
54 }
55 return bufio.NewReader(r)
56 }
57
58
59 func match(magic string, b []byte) bool {
60 if len(magic) != len(b) {
61 return false
62 }
63 for i, c := range b {
64 if magic[i] != c && magic[i] != '?' {
65 return false
66 }
67 }
68 return true
69 }
70
71
72 func sniff(r reader) format {
73 formats, _ := atomicFormats.Load().([]format)
74 for _, f := range formats {
75 b, err := r.Peek(len(f.magic))
76 if err == nil && match(f.magic, b) {
77 return f
78 }
79 }
80 return format{}
81 }
82
83
84
85
86
87 func Decode(r io.Reader) (Image, string, error) {
88 rr := asReader(r)
89 f := sniff(rr)
90 if f.decode == nil {
91 return nil, "", ErrFormat
92 }
93 m, err := f.decode(rr)
94 return m, f.name, err
95 }
96
97
98
99
100
101 func DecodeConfig(r io.Reader) (Config, string, error) {
102 rr := asReader(r)
103 f := sniff(rr)
104 if f.decodeConfig == nil {
105 return Config{}, "", ErrFormat
106 }
107 c, err := f.decodeConfig(rr)
108 return c, f.name, err
109 }
110
View as plain text