1
2
3
4
5 package decodemeta
6
7
8
9
10
11
12
13 import (
14 "bufio"
15 "crypto/md5"
16 "encoding/binary"
17 "fmt"
18 "internal/coverage"
19 "internal/coverage/slicereader"
20 "internal/coverage/stringtab"
21 "io"
22 "os"
23 )
24
25
26
27 type CoverageMetaFileReader struct {
28 f *os.File
29 hdr coverage.MetaFileHeader
30 tmp []byte
31 pkgOffsets []uint64
32 pkgLengths []uint64
33 strtab *stringtab.Reader
34 fileRdr *bufio.Reader
35 fileView []byte
36 debug bool
37 }
38
39
40
41
42
43
44
45 func NewCoverageMetaFileReader(f *os.File, fileView []byte) (*CoverageMetaFileReader, error) {
46 r := &CoverageMetaFileReader{
47 f: f,
48 fileView: fileView,
49 tmp: make([]byte, 256),
50 }
51
52 if err := r.readFileHeader(); err != nil {
53 return nil, err
54 }
55 return r, nil
56 }
57
58 func (r *CoverageMetaFileReader) readFileHeader() error {
59 var err error
60
61 r.fileRdr = bufio.NewReader(r.f)
62
63
64 if err := binary.Read(r.fileRdr, binary.LittleEndian, &r.hdr); err != nil {
65 return err
66 }
67
68
69 m := r.hdr.Magic
70 g := coverage.CovMetaMagic
71 if m[0] != g[0] || m[1] != g[1] || m[2] != g[2] || m[3] != g[3] {
72 return fmt.Errorf("invalid meta-data file magic string")
73 }
74
75
76
77 if r.hdr.Version > coverage.MetaFileVersion {
78 return fmt.Errorf("meta-data file withn unknown version %d (expected %d)", r.hdr.Version, coverage.MetaFileVersion)
79 }
80
81
82 r.pkgOffsets = make([]uint64, r.hdr.Entries)
83 for i := uint64(0); i < r.hdr.Entries; i++ {
84 if r.pkgOffsets[i], err = r.rdUint64(); err != nil {
85 return err
86 }
87 if r.pkgOffsets[i] > r.hdr.TotalLength {
88 return fmt.Errorf("insane pkg offset %d: %d > totlen %d",
89 i, r.pkgOffsets[i], r.hdr.TotalLength)
90 }
91 }
92 r.pkgLengths = make([]uint64, r.hdr.Entries)
93 for i := uint64(0); i < r.hdr.Entries; i++ {
94 if r.pkgLengths[i], err = r.rdUint64(); err != nil {
95 return err
96 }
97 if r.pkgLengths[i] > r.hdr.TotalLength {
98 return fmt.Errorf("insane pkg length %d: %d > totlen %d",
99 i, r.pkgLengths[i], r.hdr.TotalLength)
100 }
101 }
102
103
104 b := make([]byte, r.hdr.StrTabLength)
105 nr, err := r.fileRdr.Read(b)
106 if err != nil {
107 return err
108 }
109 if nr != int(r.hdr.StrTabLength) {
110 return fmt.Errorf("error: short read on string table")
111 }
112 slr := slicereader.NewReader(b, false )
113 r.strtab = stringtab.NewReader(slr)
114 r.strtab.Read()
115
116 if r.debug {
117 fmt.Fprintf(os.Stderr, "=-= read-in header is: %+v\n", *r)
118 }
119
120 return nil
121 }
122
123 func (r *CoverageMetaFileReader) rdUint64() (uint64, error) {
124 r.tmp = r.tmp[:0]
125 r.tmp = append(r.tmp, make([]byte, 8)...)
126 n, err := r.fileRdr.Read(r.tmp)
127 if err != nil {
128 return 0, err
129 }
130 if n != 8 {
131 return 0, fmt.Errorf("premature end of file on read")
132 }
133 v := binary.LittleEndian.Uint64(r.tmp)
134 return v, nil
135 }
136
137
138
139 func (r *CoverageMetaFileReader) NumPackages() uint64 {
140 return r.hdr.Entries
141 }
142
143
144
145
146 func (r *CoverageMetaFileReader) CounterMode() coverage.CounterMode {
147 return r.hdr.CMode
148 }
149
150
151
152
153 func (r *CoverageMetaFileReader) CounterGranularity() coverage.CounterGranularity {
154 return r.hdr.CGranularity
155 }
156
157
158
159
160 func (r *CoverageMetaFileReader) FileHash() [16]byte {
161 return r.hdr.MetaFileHash
162 }
163
164
165
166
167
168
169
170
171 func (r *CoverageMetaFileReader) GetPackageDecoder(pkIdx uint32, payloadbuf []byte) (*CoverageMetaDataDecoder, []byte, error) {
172 pp, err := r.GetPackagePayload(pkIdx, payloadbuf)
173 if r.debug {
174 fmt.Fprintf(os.Stderr, "=-= pkidx=%d payload length is %d hash=%s\n",
175 pkIdx, len(pp), fmt.Sprintf("%x", md5.Sum(pp)))
176 }
177 if err != nil {
178 return nil, nil, err
179 }
180 mdd, err := NewCoverageMetaDataDecoder(pp, r.fileView != nil)
181 if err != nil {
182 return nil, nil, err
183 }
184 return mdd, pp, nil
185 }
186
187
188
189
190
191
192
193
194 func (r *CoverageMetaFileReader) GetPackagePayload(pkIdx uint32, payloadbuf []byte) ([]byte, error) {
195
196
197 if uint64(pkIdx) >= r.hdr.Entries {
198 return nil, fmt.Errorf("GetPackagePayload: illegal pkg index %d", pkIdx)
199 }
200 off := r.pkgOffsets[pkIdx]
201 len := r.pkgLengths[pkIdx]
202
203 if r.debug {
204 fmt.Fprintf(os.Stderr, "=-= for pk %d, off=%d len=%d\n", pkIdx, off, len)
205 }
206
207 if r.fileView != nil {
208 return r.fileView[off : off+len], nil
209 }
210
211 payload := payloadbuf[:0]
212 if cap(payload) < int(len) {
213 payload = make([]byte, 0, len)
214 }
215 payload = append(payload, make([]byte, len)...)
216 if _, err := r.f.Seek(int64(off), io.SeekStart); err != nil {
217 return nil, err
218 }
219 if _, err := io.ReadFull(r.f, payload); err != nil {
220 return nil, err
221 }
222 return payload, nil
223 }
224
View as plain text