...
1 package mimetype
2
3 import (
4 "mime"
5
6 "github.com/gabriel-vasile/mimetype/internal/charset"
7 "github.com/gabriel-vasile/mimetype/internal/magic"
8 )
9
10
11
12 type MIME struct {
13 mime string
14 aliases []string
15 extension string
16
17
18 detector magic.Detector
19 children []*MIME
20 parent *MIME
21 }
22
23
24 func (m *MIME) String() string {
25 return m.mime
26 }
27
28
29
30
31 func (m *MIME) Extension() string {
32 return m.extension
33 }
34
35
36
37
38
39
40
41
42 func (m *MIME) Parent() *MIME {
43 return m.parent
44 }
45
46
47
48
49
50 func (m *MIME) Is(expectedMIME string) bool {
51
52
53 expectedMIME, _, _ = mime.ParseMediaType(expectedMIME)
54 found, _, _ := mime.ParseMediaType(m.mime)
55
56 if expectedMIME == found {
57 return true
58 }
59
60 for _, alias := range m.aliases {
61 if alias == expectedMIME {
62 return true
63 }
64 }
65
66 return false
67 }
68
69 func newMIME(
70 mime, extension string,
71 detector magic.Detector,
72 children ...*MIME) *MIME {
73 m := &MIME{
74 mime: mime,
75 extension: extension,
76 detector: detector,
77 children: children,
78 }
79
80 for _, c := range children {
81 c.parent = m
82 }
83
84 return m
85 }
86
87 func (m *MIME) alias(aliases ...string) *MIME {
88 m.aliases = aliases
89 return m
90 }
91
92
93
94 func (m *MIME) match(in []byte, readLimit uint32) *MIME {
95 for _, c := range m.children {
96 if c.detector(in, readLimit) {
97 return c.match(in, readLimit)
98 }
99 }
100
101 needsCharset := map[string]func([]byte) string{
102 "text/plain": charset.FromPlain,
103 "text/html": charset.FromHTML,
104 "text/xml": charset.FromXML,
105 }
106
107 ps := map[string]string{}
108 if f, ok := needsCharset[m.mime]; ok {
109 if cset := f(in); cset != "" {
110 ps["charset"] = cset
111 }
112 }
113
114 return m.cloneHierarchy(ps)
115 }
116
117
118 func (m *MIME) flatten() []*MIME {
119 out := []*MIME{m}
120 for _, c := range m.children {
121 out = append(out, c.flatten()...)
122 }
123
124 return out
125 }
126
127
128 func (m *MIME) clone(ps map[string]string) *MIME {
129 clonedMIME := m.mime
130 if len(ps) > 0 {
131 clonedMIME = mime.FormatMediaType(m.mime, ps)
132 }
133
134 return &MIME{
135 mime: clonedMIME,
136 aliases: m.aliases,
137 extension: m.extension,
138 }
139 }
140
141
142
143 func (m *MIME) cloneHierarchy(ps map[string]string) *MIME {
144 ret := m.clone(ps)
145 lastChild := ret
146 for p := m.Parent(); p != nil; p = p.Parent() {
147 pClone := p.clone(nil)
148 lastChild.parent = pClone
149 lastChild = pClone
150 }
151
152 return ret
153 }
154
155 func (m *MIME) lookup(mime string) *MIME {
156 for _, n := range append(m.aliases, m.mime) {
157 if n == mime {
158 return m
159 }
160 }
161
162 for _, c := range m.children {
163 if m := c.lookup(mime); m != nil {
164 return m
165 }
166 }
167 return nil
168 }
169
170
171
172
173
174 func (m *MIME) Extend(detector func(raw []byte, limit uint32) bool, mime, extension string, aliases ...string) {
175 c := &MIME{
176 mime: mime,
177 extension: extension,
178 detector: detector,
179 parent: m,
180 aliases: aliases,
181 }
182
183 mu.Lock()
184 m.children = append([]*MIME{c}, m.children...)
185 mu.Unlock()
186 }
187
View as plain text