Skip to content

Commit f5b6ce9

Browse files
committed
Added a writer to allow users to easily tee a reader through this library
1 parent 2248f2e commit f5b6ce9

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

Diff for: filetype_test.go

+39
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package filetype
22

33
import (
4+
"bytes"
5+
"io"
46
"testing"
57

68
"github.com/h2non/filetype/types"
@@ -121,3 +123,40 @@ func TestGetType(t *testing.T) {
121123
t.Fatalf("Type should not be supported")
122124
}
123125
}
126+
127+
func TestMatchWriter(t *testing.T) {
128+
cases := []struct {
129+
mime string
130+
reader io.Reader
131+
read int64
132+
err error
133+
}{
134+
{"image/jpeg", bytes.NewReader([]byte{0xFF, 0xD8, 0xFF}), 3, nil},
135+
{"image/png", bytes.NewReader([]byte{0x89, 0x50, 0x4E, 0x47}), 4, nil},
136+
{types.Unknown.MIME.Value, bytes.NewReader([]byte{}), 0, ErrEmptyBuffer},
137+
{types.Unknown.MIME.Value, nil, 0, ErrEmptyBuffer},
138+
}
139+
for _, test := range cases {
140+
var w int64
141+
var err error
142+
var mimeType types.Type
143+
mw := NewMatcherWriter()
144+
if test.reader != nil {
145+
w, err = io.Copy(mw, test.reader)
146+
}
147+
if err != nil {
148+
t.Fatalf("Error matching %s error: %v", test.mime, err)
149+
return
150+
}
151+
mimeType, err = mw.Match()
152+
if err != test.err {
153+
t.Fatalf("Invalid error match: %v, expected %s", err, test.err)
154+
}
155+
if mimeType.MIME.Value != test.mime {
156+
t.Fatalf("Invalid mime match: %s, expected %s", mimeType.MIME.Value, test.mime)
157+
}
158+
if w != test.read {
159+
t.Fatalf("Invalid read match: %d, expected %d", w, test.read)
160+
}
161+
}
162+
}

Diff for: match.go

+45
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package filetype
22

33
import (
44
"io"
5+
"math"
56
"os"
67

78
"github.com/h2non/filetype/matchers"
@@ -17,6 +18,50 @@ var MatcherKeys = &matchers.MatcherKeys
1718
// NewMatcher is an alias to matchers.NewMatcher
1819
var NewMatcher = matchers.NewMatcher
1920

21+
const maxBufSize = 8192
22+
23+
// MatcherWriter is a matcher that coplies to the writer interface
24+
type MatcherWriter struct {
25+
buf []byte
26+
}
27+
28+
func (mb *MatcherWriter) Write(p []byte) (n int, err error) {
29+
incomingSize := len(p)
30+
written := incomingSize
31+
currentSize := len(mb.buf)
32+
if currentSize < maxBufSize {
33+
// write only when the current size of the buffer is less than the max buffer size
34+
newSize := currentSize + incomingSize
35+
written = maxBufSize - newSize
36+
reSlice := p
37+
if written < 0 {
38+
// if the maxBufSize is exceeded by the new size, we need to do some re slicing
39+
written = int(math.Abs(float64(written)))
40+
reSlice = p[0:written]
41+
} else {
42+
// if the maxBufSize is not exceeded then we are going to write the whole buffer
43+
written = incomingSize
44+
}
45+
mb.buf = append(mb.buf, reSlice...)
46+
}
47+
return written, nil
48+
}
49+
50+
// Match calls the Match function with the inner buffer of the MatcherWriter
51+
func (mb *MatcherWriter) Match() (types.Type, error) {
52+
if mb.buf == nil {
53+
return types.Unknown, ErrEmptyBuffer
54+
}
55+
return Match(mb.buf)
56+
}
57+
58+
// NewMatcherWriter creates a matcher which is a io.Writer
59+
func NewMatcherWriter() *MatcherWriter {
60+
return &MatcherWriter{
61+
buf: make([]byte, 0, maxBufSize),
62+
}
63+
}
64+
2065
// Match infers the file type of a given buffer inspecting its magic numbers signature
2166
func Match(buf []byte) (types.Type, error) {
2267
length := len(buf)

0 commit comments

Comments
 (0)