limage - xcf/reader.go
1 package xcf
2
3 import (
4 "errors"
5 "io"
6 "unicode/utf8"
7
8 "vimagination.zapto.org/byteio"
9 )
10
11 type reader struct {
12 *byteio.StickyBigEndianReader
13 rs *readSeeker
14 }
15
16 type readSeeker struct {
17 io.ReaderAt
18 pos int64
19 }
20
21 func (r *readSeeker) Read(p []byte) (int, error) {
22 n, err := r.ReadAt(p, r.pos)
23 r.pos += int64(n)
24 return n, err
25 }
26
27 func newReader(r io.ReaderAt) reader {
28 nr := reader{
29 rs: &readSeeker{ReaderAt: r},
30 }
31 nr.StickyBigEndianReader = &byteio.StickyBigEndianReader{Reader: nr.rs}
32 return nr
33 }
34
35 const maxString = 16 * 1024 * 1024
36
37 func (r *reader) ReadString() string {
38 length := r.ReadUint32()
39 if length == 0 {
40 return ""
41 } else if length > maxString {
42 r.SetError(ErrStringTooLong)
43 return ""
44 }
45 b := make([]byte, length)
46 _, err := io.ReadFull(r, b)
47 if err != nil {
48 r.Err = err
49 return ""
50 }
51 if b[length-1] != 0 || !utf8.Valid(b[:length-1]) {
52 r.SetError(ErrInvalidString)
53 return ""
54 }
55 return string(b[:length-1])
56 }
57
58 func (r *reader) ReadByte() byte {
59 return r.ReadUint8()
60 }
61
62 func (r *reader) Goto(n uint64) {
63 r.rs.pos = int64(n)
64 }
65
66 func (r *reader) SetError(err error) {
67 if r.Err == nil {
68 r.Err = err
69 }
70 }
71
72 // Errors
73 var (
74 ErrInvalidString = errors.New("string is invalid")
75 ErrStringTooLong = errors.New("string exceeds maximum length")
76 ErrInvalidSeek = errors.New("invalid seek")
77 )
78