package decodemeta
import (
"bufio"
"crypto/md5"
"encoding/binary"
"fmt"
"internal/coverage"
"internal/coverage/slicereader"
"internal/coverage/stringtab"
"io"
"os"
)
type CoverageMetaFileReader struct {
f *os .File
hdr coverage .MetaFileHeader
tmp []byte
pkgOffsets []uint64
pkgLengths []uint64
strtab *stringtab .Reader
fileRdr *bufio .Reader
fileView []byte
debug bool
}
func NewCoverageMetaFileReader (f *os .File , fileView []byte ) (*CoverageMetaFileReader , error ) {
r := &CoverageMetaFileReader {
f : f ,
fileView : fileView ,
tmp : make ([]byte , 256 ),
}
if err := r .readFileHeader (); err != nil {
return nil , err
}
return r , nil
}
func (r *CoverageMetaFileReader ) readFileHeader () error {
var err error
r .fileRdr = bufio .NewReader (r .f )
if err := binary .Read (r .fileRdr , binary .LittleEndian , &r .hdr ); err != nil {
return err
}
m := r .hdr .Magic
g := coverage .CovMetaMagic
if m [0 ] != g [0 ] || m [1 ] != g [1 ] || m [2 ] != g [2 ] || m [3 ] != g [3 ] {
return fmt .Errorf ("invalid meta-data file magic string" )
}
if r .hdr .Version > coverage .MetaFileVersion {
return fmt .Errorf ("meta-data file withn unknown version %d (expected %d)" , r .hdr .Version , coverage .MetaFileVersion )
}
r .pkgOffsets = make ([]uint64 , r .hdr .Entries )
for i := uint64 (0 ); i < r .hdr .Entries ; i ++ {
if r .pkgOffsets [i ], err = r .rdUint64 (); err != nil {
return err
}
if r .pkgOffsets [i ] > r .hdr .TotalLength {
return fmt .Errorf ("insane pkg offset %d: %d > totlen %d" ,
i , r .pkgOffsets [i ], r .hdr .TotalLength )
}
}
r .pkgLengths = make ([]uint64 , r .hdr .Entries )
for i := uint64 (0 ); i < r .hdr .Entries ; i ++ {
if r .pkgLengths [i ], err = r .rdUint64 (); err != nil {
return err
}
if r .pkgLengths [i ] > r .hdr .TotalLength {
return fmt .Errorf ("insane pkg length %d: %d > totlen %d" ,
i , r .pkgLengths [i ], r .hdr .TotalLength )
}
}
b := make ([]byte , r .hdr .StrTabLength )
nr , err := r .fileRdr .Read (b )
if err != nil {
return err
}
if nr != int (r .hdr .StrTabLength ) {
return fmt .Errorf ("error: short read on string table" )
}
slr := slicereader .NewReader (b , false )
r .strtab = stringtab .NewReader (slr )
r .strtab .Read ()
if r .debug {
fmt .Fprintf (os .Stderr , "=-= read-in header is: %+v\n" , *r )
}
return nil
}
func (r *CoverageMetaFileReader ) rdUint64 () (uint64 , error ) {
r .tmp = r .tmp [:0 ]
r .tmp = append (r .tmp , make ([]byte , 8 )...)
n , err := r .fileRdr .Read (r .tmp )
if err != nil {
return 0 , err
}
if n != 8 {
return 0 , fmt .Errorf ("premature end of file on read" )
}
v := binary .LittleEndian .Uint64 (r .tmp )
return v , nil
}
func (r *CoverageMetaFileReader ) NumPackages () uint64 {
return r .hdr .Entries
}
func (r *CoverageMetaFileReader ) CounterMode () coverage .CounterMode {
return r .hdr .CMode
}
func (r *CoverageMetaFileReader ) CounterGranularity () coverage .CounterGranularity {
return r .hdr .CGranularity
}
func (r *CoverageMetaFileReader ) FileHash () [16 ]byte {
return r .hdr .MetaFileHash
}
func (r *CoverageMetaFileReader ) GetPackageDecoder (pkIdx uint32 , payloadbuf []byte ) (*CoverageMetaDataDecoder , []byte , error ) {
pp , err := r .GetPackagePayload (pkIdx , payloadbuf )
if r .debug {
fmt .Fprintf (os .Stderr , "=-= pkidx=%d payload length is %d hash=%s\n" ,
pkIdx , len (pp ), fmt .Sprintf ("%x" , md5 .Sum (pp )))
}
if err != nil {
return nil , nil , err
}
mdd , err := NewCoverageMetaDataDecoder (pp , r .fileView != nil )
if err != nil {
return nil , nil , err
}
return mdd , pp , nil
}
func (r *CoverageMetaFileReader ) GetPackagePayload (pkIdx uint32 , payloadbuf []byte ) ([]byte , error ) {
if uint64 (pkIdx ) >= r .hdr .Entries {
return nil , fmt .Errorf ("GetPackagePayload: illegal pkg index %d" , pkIdx )
}
off := r .pkgOffsets [pkIdx ]
len := r .pkgLengths [pkIdx ]
if r .debug {
fmt .Fprintf (os .Stderr , "=-= for pk %d, off=%d len=%d\n" , pkIdx , off , len )
}
if r .fileView != nil {
return r .fileView [off : off +len ], nil
}
payload := payloadbuf [:0 ]
if cap (payload ) < int (len ) {
payload = make ([]byte , 0 , len )
}
payload = append (payload , make ([]byte , len )...)
if _ , err := r .f .Seek (int64 (off ), io .SeekStart ); err != nil {
return nil , err
}
if _ , err := io .ReadFull (r .f , payload ); err != nil {
return nil , err
}
return payload , nil
}
The pages are generated with Golds v0.7.0-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .