1
2
3
4
5 package encodemeta
6
7 import (
8 "bufio"
9 "encoding/binary"
10 "fmt"
11 "hash/fnv"
12 "internal/coverage"
13 "internal/coverage/stringtab"
14 "io"
15 "os"
16 "unsafe"
17 )
18
19
20
21
22
23 type CoverageMetaFileWriter struct {
24 stab stringtab.Writer
25 mfname string
26 w *bufio.Writer
27 tmp []byte
28 debug bool
29 }
30
31 func NewCoverageMetaFileWriter(mfname string, w io.Writer) *CoverageMetaFileWriter {
32 r := &CoverageMetaFileWriter{
33 mfname: mfname,
34 w: bufio.NewWriter(w),
35 tmp: make([]byte, 64),
36 }
37 r.stab.InitWriter()
38 r.stab.Lookup("")
39 return r
40 }
41
42 func (m *CoverageMetaFileWriter) Write(finalHash [16]byte, blobs [][]byte, mode coverage.CounterMode, granularity coverage.CounterGranularity) error {
43 mhsz := uint64(unsafe.Sizeof(coverage.MetaFileHeader{}))
44 stSize := m.stab.Size()
45 stOffset := mhsz + uint64(16*len(blobs))
46 preambleLength := stOffset + uint64(stSize)
47
48 if m.debug {
49 fmt.Fprintf(os.Stderr, "=+= sizeof(MetaFileHeader)=%d\n", mhsz)
50 fmt.Fprintf(os.Stderr, "=+= preambleLength=%d stSize=%d\n", preambleLength, stSize)
51 }
52
53
54 tlen := preambleLength
55 for i := 0; i < len(blobs); i++ {
56 tlen += uint64(len(blobs[i]))
57 }
58
59
60 mh := coverage.MetaFileHeader{
61 Magic: coverage.CovMetaMagic,
62 Version: coverage.MetaFileVersion,
63 TotalLength: tlen,
64 Entries: uint64(len(blobs)),
65 MetaFileHash: finalHash,
66 StrTabOffset: uint32(stOffset),
67 StrTabLength: stSize,
68 CMode: mode,
69 CGranularity: granularity,
70 }
71 var err error
72 if err = binary.Write(m.w, binary.LittleEndian, mh); err != nil {
73 return fmt.Errorf("error writing %s: %v", m.mfname, err)
74 }
75
76 if m.debug {
77 fmt.Fprintf(os.Stderr, "=+= len(blobs) is %d\n", mh.Entries)
78 }
79
80
81 off := preambleLength
82 off2 := mhsz
83 buf := make([]byte, 8)
84 for _, blob := range blobs {
85 binary.LittleEndian.PutUint64(buf, off)
86 if _, err = m.w.Write(buf); err != nil {
87 return fmt.Errorf("error writing %s: %v", m.mfname, err)
88 }
89 if m.debug {
90 fmt.Fprintf(os.Stderr, "=+= pkg offset %d 0x%x\n", off, off)
91 }
92 off += uint64(len(blob))
93 off2 += 8
94 }
95 for _, blob := range blobs {
96 bl := uint64(len(blob))
97 binary.LittleEndian.PutUint64(buf, bl)
98 if _, err = m.w.Write(buf); err != nil {
99 return fmt.Errorf("error writing %s: %v", m.mfname, err)
100 }
101 if m.debug {
102 fmt.Fprintf(os.Stderr, "=+= pkg len %d 0x%x\n", bl, bl)
103 }
104 off2 += 8
105 }
106
107
108 if err = m.stab.Write(m.w); err != nil {
109 return err
110 }
111
112
113 for k, blob := range blobs {
114 if m.debug {
115 h := fnv.New128a()
116 h.Write(blob)
117 fmt.Fprintf(os.Stderr, "=+= writing blob %d len %d at off=%d hash %s\n", k, len(blob), off2, fmt.Sprintf("%x", h.Sum(nil)))
118 }
119 if _, err = m.w.Write(blob); err != nil {
120 return fmt.Errorf("error writing %s: %v", m.mfname, err)
121 }
122 if m.debug {
123 fmt.Fprintf(os.Stderr, "=+= wrote package payload of %d bytes\n",
124 len(blob))
125 }
126 off2 += uint64(len(blob))
127 }
128
129
130 if err = m.w.Flush(); err != nil {
131 return fmt.Errorf("error writing %s: %v", m.mfname, err)
132 }
133 return nil
134 }
135
View as plain text